Skip to content

Fix TanStack Start compatibility - #5756

Merged
proggeramlug merged 9 commits into
mainfrom
feat/tanstack-start-compat
Aug 1, 2026
Merged

Fix TanStack Start compatibility#5756
proggeramlug merged 9 commits into
mainfrom
feat/tanstack-start-compat

Conversation

@TheHypnoo

@TheHypnoo TheHypnoo commented Jun 28, 2026

Copy link
Copy Markdown
Member

Summary

Fix TanStack Start compatibility for compiled package subpaths, React/TanStack TSX lowering, lazy route loading, and SSR response streams.

Changes

  • Honor package subpath exports before falling back to package-root source entries for compiled packages.
  • Prefer .ts, .tsx, and .mts source mirrors for JavaScript package entries, including lib/ and dist/ mirrors under src/.
  • Preserve hoisted TextEncoder/TextDecoder type inference across module and function-expression lowering, including outer-scope util aliases.
  • Keep imported react/jsx-runtime calls distinct from Perry native JSX lowering.
  • Lower React namespace imports and TanStack/React automatic TSX modules through React element creation semantics.
  • Preserve JSX spread props and collect dynamic imports inside closure bodies.
  • Add AbortSignal listener methods needed by Request handling.
  • Support expando properties on Web Streams handles.
  • Expose reflected Request/Response prototype accessors used by response wrapper libraries.
  • Preserve new Response(ReadableStream) bodies lazily so pull-driven SSR streams can be consumed by downstream readers.

Related issue

n/a

Test plan

  • cargo fmt --all -- --check

  • ./scripts/check_file_size.sh

  • cargo check -p perry-hir

  • cargo build -p perry

  • cargo test -p perry --test issue_5756_response_stream_body -- --nocapture

  • cargo test -p perry --test issue_5174_headers_http_pump_hang -- --nocapture

  • cargo test -p perry compile_package_subpath_exports_do_not_fall_back_to_src_index

  • tests/test_compile_package_exports_subpath_source.sh

  • tests/test_textencoder_hoisted_function_decl.sh

  • Compiled and served a minimal TanStack Start template through a Perry-compiled HTTP wrapper; GET / returned HTTP 200 with HTML containing Welcome to TanStack Start.

  • cargo build --release clean

  • cargo test --workspace --exclude perry-ui-ios --exclude perry-ui-tvos --exclude perry-ui-watchos --exclude perry-ui-gtk4 --exclude perry-ui-android --exclude perry-ui-windows passes

  • (if user-facing) Added or updated a test under test-files/ or a #[test] in the affected crate

  • (if CLI / stdlib / runtime API changed) Updated docs/src/ is not needed; this changes compiler/runtime compatibility for existing APIs

  • (if touching a platform UI backend) Not applicable

Screenshots / output

n/a

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md (maintainer handles these at merge)
  • My commits follow the loose feat: / fix: / docs: / chore: prefix convention used in the log
  • I've read CONTRIBUTING.md and agree to the Code of Conduct

Summary by CodeRabbit

  • New Features

    • Added automatic React JSX support for JSX/TSX modules.
    • Preserved ReadableStream bodies in Request and Response constructors.
    • Added addEventListener and removeEventListener to AbortSignal.
    • Improved fetch prototype accessors and superclass initialization.
  • Bug Fixes

    • Corrected package subpath export resolution and TypeScript source selection.
    • Fixed dynamic imports inside closures.
    • Improved util.TextEncoder and TextDecoder handling.
    • Preserved JSX spread properties and corrected imported JSX runtime calls.
    • Improved cross-module object export handling.
  • Tests

    • Added regression coverage for package exports, streaming responses, dynamic imports, and text encoding.

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 70ba78cd-5752-4c81-bbfb-fc914e15fef0

📥 Commits

Reviewing files that changed from the base of the PR and between db16840 and c76e6d9.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • CLAUDE.md
  • Cargo.toml
  • changelog.d/5756-tanstack-start-compat.md

📝 Walkthrough

Walkthrough

This PR updates package subpath resolution, JSX and hoisted variable lowering, dynamic import traversal, Fetch stream handling, Web Fetch reflection, AbortSignal methods, superclass dispatch, imported-variable classification, and regression coverage.

Changes

HIR lowering and JSX/import handling

Layer / File(s) Summary
Hoisted type helpers
crates/perry-hir/src/lower_types.rs, crates/perry-hir/src/lower_types/hoisted_text_codec.rs
Adds helpers that infer hoisted TextEncoder/TextDecoder types and extract literal require() specifiers.
Hoisted var pre-registration
crates/perry-hir/src/lower/expr_function.rs, crates/perry-hir/src/lower/lower_module_fn.rs
Tracks util aliases, infers hoisted binding types, and separates top-level and nested var prologues.
JSX and React import lowering
crates/perry-hir/src/jsx.rs, crates/perry-hir/src/lower/module_decl.rs, crates/perry-codegen/src/lower_call/extern_func.rs
Preserves JSX spread props, changes React fragment lowering, recognizes React namespace imports, and excludes imported jsx/jsxs names from the fast path.
Dynamic import traversal
crates/perry-hir/src/dynamic_import/visitors.rs
Traverses closure bodies when collecting dynamic imports.
HIR regression coverage
tests/test_textencoder_hoisted_function_decl.sh
Tests hoisted util.TextEncoder usage in top-level and nested functions.

Package subpath export resolution

Layer / File(s) Summary
Resolver changes
crates/perry/src/commands/compile/resolve.rs
Resolves declared package subpaths directly and probes .ts, .tsx, and .mts source replacements.
Resolver regression coverage
crates/perry/src/commands/compile/resolve/tests.rs, tests/test_compile_package_exports_subpath_source.sh
Tests that package subpaths use their declared source entries instead of the package root entry.

Runtime fetch, streams, and superclass dispatch

Layer / File(s) Summary
Fetch body stream lifecycle
crates/perry-stdlib/src/fetch/*
Stores pending ReadableStream handles on responses and drains them during later body consumption.
Superclass and prototype setup
crates/perry-runtime/src/object/global_this/fetch_globals.rs, crates/perry-runtime/src/object/global_this/proto_methods.rs
Updates superclass recovery and installs Fetch accessor descriptors.
AbortSignal listeners
crates/perry-runtime/src/url/abort.rs
Adds addEventListener and removeEventListener methods to AbortSignal.
Runtime regression coverage
crates/perry/tests/issue_5756_response_stream_body.rs
Tests pull-driven response bodies and Fetch prototype accessors.

Compile pipeline import classification

Layer / File(s) Summary
Imported variable classification
crates/perry/src/commands/compile/run_pipeline.rs
Recognizes imported names exported as objects by the source module.

Release metadata

Layer / File(s) Summary
Version and changelog
Cargo.toml, CLAUDE.md, changelog.d/5756-tanstack-start-compat.md
Updates the version to 0.5.1276 and records the compatibility changes.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReadableStream
  participant ResponseConstructor
  participant FetchResponse
  participant ResponseBody
  ReadableStream->>ResponseConstructor: pass stream handle
  ResponseConstructor->>FetchResponse: store body_stream_id
  ResponseBody->>FetchResponse: read stored stream id
  FetchResponse->>ReadableStream: drain stream bytes
Loading

Possibly related PRs

Suggested labels: rust

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the PR's main goal: TanStack Start compatibility fixes.
Description check ✅ Passed The description follows the template well, with all required sections filled and concrete summary, changes, and test plan details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tanstack-start-compat

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.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/perry/src/commands/compile/resolve.rs (1)

599-628: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Handle .tsx and .mts mirrors here too.

resolve_with_extensions prefers .ts, .tsx, and .mts, but this helper only probes .ts. A compile-package export that resolves to dist/foo.js with source at src/foo.tsx or src/foo.mts will still stay on JS here, so the subpath misses native source resolution.

Proposed fix
 fn prefer_ts_source_for_package_entry(
     package_dir: &Path,
     normal_entry: PathBuf,
 ) -> Option<PathBuf> {
     if is_js_file(&normal_entry) {
-        // Try .ts equivalent of the .js entry
-        let ts_path = normal_entry.with_extension("ts");
-        if ts_path.exists() {
-            return Some(ts_path);
+        for ext in ["ts", "tsx", "mts"] {
+            let ts_path = normal_entry.with_extension(ext);
+            if ts_path.exists() && ts_path.is_file() {
+                return Some(ts_path);
+            }
         }
         // Check src/ directory mirror of lib/ or dist/ path
         if let Ok(rel) = normal_entry.strip_prefix(package_dir) {
             let rel_str = rel.to_string_lossy();
             if rel_str.starts_with("lib") || rel_str.starts_with("dist") {
@@
                 };
                 if let Ok(rest) = stripped {
-                    let src_equiv = package_dir.join("src").join(rest).with_extension("ts");
-                    if src_equiv.exists() {
-                        return Some(src_equiv);
+                    for ext in ["ts", "tsx", "mts"] {
+                        let src_equiv = package_dir.join("src").join(rest).with_extension(ext);
+                        if src_equiv.exists() && src_equiv.is_file() {
+                            return Some(src_equiv);
+                        }
                     }
                 }
             }
         }
     }
🤖 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/src/commands/compile/resolve.rs` around lines 599 - 628, Update
prefer_ts_source_for_package_entry so it probes native TypeScript mirrors for
.js package entries, not just .ts. When is_js_file(normal_entry) is true, check
the .ts, .tsx, and .mts equivalents of the entry, and also the src mirror for
lib/dist paths using the same set of extensions. Keep the existing control flow
in prefer_ts_source_for_package_entry and ensure resolve_with_extensions stays
aligned with the source-file preference logic.
🤖 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/lower/expr_function.rs`:
- Around line 779-789: The hoisted type inference in
infer_hoisted_text_codec_var_type only checks builtin aliases recorded in the
current var pre-pass, so util references from outer scope still resolve to Any.
Update the logic in expr_function.rs to consult LoweringContext for util aliases
as well, matching the module-level handling by using
ctx.lookup_builtin_module_alias and ctx.lookup_native_module alongside the
existing builtin_aliases_in_var_decl predicate. Keep the current var-declaration
alias tracking, but widen the check around decl.init / ident handling so util
and node:util are recognized even when imported or required outside the local
pre-pass.

---

Outside diff comments:
In `@crates/perry/src/commands/compile/resolve.rs`:
- Around line 599-628: Update prefer_ts_source_for_package_entry so it probes
native TypeScript mirrors for .js package entries, not just .ts. When
is_js_file(normal_entry) is true, check the .ts, .tsx, and .mts equivalents of
the entry, and also the src mirror for lib/dist paths using the same set of
extensions. Keep the existing control flow in prefer_ts_source_for_package_entry
and ensure resolve_with_extensions stays aligned with the source-file preference
logic.
🪄 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: 211f40fc-7814-4057-b8e0-94a47b7ac54f

📥 Commits

Reviewing files that changed from the base of the PR and between 0e89645 and ca92bdb.

📒 Files selected for processing (7)
  • crates/perry-hir/src/lower/expr_function.rs
  • crates/perry-hir/src/lower/lower_module_fn.rs
  • crates/perry-hir/src/lower_types.rs
  • crates/perry/src/commands/compile/resolve.rs
  • crates/perry/src/commands/compile/resolve/tests.rs
  • tests/test_compile_package_exports_subpath_source.sh
  • tests/test_textencoder_hoisted_function_decl.sh

Comment thread crates/perry-hir/src/lower/expr_function.rs
@TheHypnoo
TheHypnoo marked this pull request as draft June 28, 2026 10:58
@TheHypnoo TheHypnoo changed the title Fix TanStack Start package compatibility Fix TanStack Start compatibility Jun 28, 2026
@TheHypnoo
TheHypnoo marked this pull request as ready for review June 28, 2026 16:02

@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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/perry-stdlib/src/fetch/request_ctor.rs (1)

50-56: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reject GET/HEAD stream bodies before draining them.

Line 50 drains a pending ReadableStream before the Line 55 GET/HEAD guard. A lazy stream can be consumed or block even though the constructor is about to throw.

Defer draining until after the method/body validation
-    let body: Option<Vec<u8>> = take_pending_fetch_body_stream_id()
-        .map(crate::streams::drain_readable_into_bytes)
-        .or_else(|| dispatch::body_addr_buffer_bytes(body_ptr as usize))
-        .or_else(|| dispatch::body_bytes_from_header(body_ptr));
+    let pending_stream_id = take_pending_fetch_body_stream_id();
+    let non_stream_body = if pending_stream_id.is_none() {
+        dispatch::body_addr_buffer_bytes(body_ptr as usize)
+            .or_else(|| dispatch::body_bytes_from_header(body_ptr))
+    } else {
+        None
+    };
     // GET/HEAD requests may not carry a body (WHATWG fetch). Refs `#2643`.
-    if body.is_some() && (method == "GET" || method == "HEAD") {
+    if (pending_stream_id.is_some() || non_stream_body.is_some())
+        && (method == "GET" || method == "HEAD")
+    {
         throw_fetch_type_error("Request with GET/HEAD method cannot have body.");
     }
+    let body = pending_stream_id
+        .map(crate::streams::drain_readable_into_bytes)
+        .or(non_stream_body);
🤖 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-stdlib/src/fetch/request_ctor.rs` around lines 50 - 56, The
Request constructor logic in request_ctor should validate the method before
consuming any pending body stream. Move the GET/HEAD body check ahead of the
take_pending_fetch_body_stream_id/drain_readable_into_bytes path so a lazy
ReadableStream is not drained or blocked when the constructor will throw anyway.
Keep the existing body sources and throw_fetch_type_error behavior intact, but
ensure the method/body validation gates access to stream draining in this
constructor flow.
crates/perry-stdlib/src/fetch/mod.rs (1)

1333-1355: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Don’t silently drop stream-backed bodies when cloning.

For new Response(readableStream), resp.body is empty and the payload lives only in resp.body_stream_id. This clone keeps body_present: true but sets body_stream_id: None, so the clone exposes an empty body. Either tee/copy the stream state or throw until stream teeing is supported.

Minimal guard to avoid silent data loss
         guard.get(&id).map(|resp| {
             if resp.body_present && resp.body_used {
                 unsafe {
                     throw_fetch_type_error("Response.clone: Body has already been consumed.")
                 };
             }
+            if resp.body_stream_id.is_some() {
+                unsafe {
+                    throw_fetch_type_error("Response.clone: streaming bodies are not yet cloneable.")
+                };
+            }
             FetchResponse {
🤖 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-stdlib/src/fetch/mod.rs` around lines 1333 - 1355,
js_response_clone currently clones stream-backed responses incorrectly by
copying only resp.body and clearing body_stream_id, which makes
Response(readableStream) clones lose their payload. Update the cloning logic in
js_response_clone/FetchResponse so stream-backed bodies are either properly
tee’d/copied along with body_stream_id (and related stream state) or, if that
isn’t supported yet, throw a type error instead of returning an empty clone. Use
the existing FetchResponse fields and the body_present/body_used checks to
locate the fix.
🤖 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-codegen/src/lower_call/extern_func.rs`:
- Around line 1353-1356: The JSX fast-path in ExternFuncRef handling is only
excluding ctx.imported_vars, so imported cross-module jsx/jsxs calls can still
be rewritten incorrectly. Update the guard in lower_call/extern_func.rs around
try_rewrite_perry_tui_jsx_intrinsic to also skip names that are imported via
ctx.import_function_prefixes, ensuring imported jsx/jsxs bindings are not routed
to js_jsx/js_jsxs but left as normal imported calls.

In `@crates/perry-hir/src/lower/lower_module_fn.rs`:
- Around line 30-39: The React import detection in lower_module_fn currently
treats all imports from "react" as runtime imports, so type-only React imports
still set has_explicit_react_import. Update the import scan in the
lower_module_fn logic to ignore type-only imports by checking import.type_only
and any named specifiers’ is_type_only flags before marking React as available,
so only real runtime React imports prevent the synthetic namespace import.

In `@crates/perry-hir/src/lower/module_decl.rs`:
- Around line 425-433: The React namespace import handling in module_decl.rs is
currently binding type-only imports into `react_default_import_local`, which can
leave JSX lowering pointing at a runtime React symbol that does not exist.
Update the `source == "react"` branch in the import lowering logic to skip this
assignment when `whole_decl_type_only` is true, so only real runtime React
namespace imports populate `ctx.react_default_import_local`. Keep the existing
behavior for non-type-only React namespace imports and leave the JSX lowering
path unchanged otherwise.

In `@crates/perry-runtime/src/object/field_set_by_name.rs`:
- Around line 396-418: Move the Web Streams setter handling in
`field_set_by_name` so it runs before any early primitive-value return path; the
current `f64::from_bits`/`stream_handle_probe` block can exit before
`handle_property_set_dispatch` is invoked for finite numeric stream ids. Keep
the same stream-id detection logic, but ensure expando writes like
`stream.allReady = ...` reach the dispatch callback instead of being treated as
plain numbers.

In `@crates/perry-runtime/src/object/global_this/fetch_globals.rs`:
- Around line 507-545: The helper is out of sync with the builtin class-ID
mapping: `is_uncallable_builtin_super_parent_class_id` includes entries that
`global_builtin_constructor_class_id` cannot resolve for `WeakMap`, `WeakSet`,
`SharedArrayBuffer`, and `DataView`. Update the builtin ID handling so these
constructors are recognized consistently, or remove the unreachable names from
the `NAMES` list, ensuring the logic in
`is_uncallable_builtin_super_parent_class_id` matches the IDs returned by
`global_builtin_constructor_class_id`.

In `@crates/perry/src/commands/compile/run_pipeline.rs`:
- Around line 2765-2768: The named-import resolution in the compile pipeline is
bypassing the function-declaration filter by checking
source_module.exported_objects directly, which can reintroduce exported function
names that exported_var_names intentionally excludes. Update the import/export
matching logic in run_pipeline so the immediate source-module path uses
exported_var_names or applies the same is_function_decl exclusion before
treating a symbol as a variable export. Keep the fix localized to the code that
decides whether origin_key is considered exported for named imports, so
callback/value imports don’t get miscompiled as variable imports.

---

Outside diff comments:
In `@crates/perry-stdlib/src/fetch/mod.rs`:
- Around line 1333-1355: js_response_clone currently clones stream-backed
responses incorrectly by copying only resp.body and clearing body_stream_id,
which makes Response(readableStream) clones lose their payload. Update the
cloning logic in js_response_clone/FetchResponse so stream-backed bodies are
either properly tee’d/copied along with body_stream_id (and related stream
state) or, if that isn’t supported yet, throw a type error instead of returning
an empty clone. Use the existing FetchResponse fields and the
body_present/body_used checks to locate the fix.

In `@crates/perry-stdlib/src/fetch/request_ctor.rs`:
- Around line 50-56: The Request constructor logic in request_ctor should
validate the method before consuming any pending body stream. Move the GET/HEAD
body check ahead of the
take_pending_fetch_body_stream_id/drain_readable_into_bytes path so a lazy
ReadableStream is not drained or blocked when the constructor will throw anyway.
Keep the existing body sources and throw_fetch_type_error behavior intact, but
ensure the method/body validation gates access to stream draining in this
constructor flow.
🪄 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: dc637be5-c979-4a8c-83f6-f465ebf59911

📥 Commits

Reviewing files that changed from the base of the PR and between 7d59714 and db16840.

📒 Files selected for processing (20)
  • crates/perry-codegen/src/lower_call/extern_func.rs
  • crates/perry-hir/src/dynamic_import/visitors.rs
  • crates/perry-hir/src/jsx.rs
  • crates/perry-hir/src/lower/expr_function.rs
  • crates/perry-hir/src/lower/lower_module_fn.rs
  • crates/perry-hir/src/lower/module_decl.rs
  • crates/perry-runtime/src/object/field_get_set/get_field_by_name.rs
  • crates/perry-runtime/src/object/field_set_by_name.rs
  • crates/perry-runtime/src/object/global_this/fetch_globals.rs
  • crates/perry-runtime/src/object/global_this/proto_methods.rs
  • crates/perry-runtime/src/proxy/put_value.rs
  • crates/perry-runtime/src/url/abort.rs
  • crates/perry-stdlib/src/common/dispatch/property_dispatch.rs
  • crates/perry-stdlib/src/fetch/abort_bridge.rs
  • crates/perry-stdlib/src/fetch/body_metadata.rs
  • crates/perry-stdlib/src/fetch/dispatch.rs
  • crates/perry-stdlib/src/fetch/mod.rs
  • crates/perry-stdlib/src/fetch/request_ctor.rs
  • crates/perry/src/commands/compile/run_pipeline.rs
  • crates/perry/tests/issue_5756_response_stream_body.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/perry-stdlib/src/fetch/body_metadata.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry-hir/src/lower/expr_function.rs

Comment thread crates/perry-codegen/src/lower_call/extern_func.rs Outdated
Comment thread crates/perry-hir/src/lower/lower_module_fn.rs
Comment thread crates/perry-hir/src/lower/module_decl.rs
Comment thread crates/perry-runtime/src/object/field_set_by_name.rs Outdated
Comment thread crates/perry-runtime/src/object/global_this/fetch_globals.rs
Comment thread crates/perry/src/commands/compile/run_pipeline.rs Outdated
@TheHypnoo
TheHypnoo marked this pull request as draft June 28, 2026 17:02
@proggeramlug

Copy link
Copy Markdown
Contributor

Ran this against current main to work out exactly what a rebase needs. It's three conflicts and two file-size violations, and two of them share a fix. Posting the map so the rebase is mechanical.

Conflicts

1. perry-runtime/src/array/generic.rs — take main's side, then delete your helper.
main landed the same feature independently (#5989) as generic_mutators::arraylike_collection_foreach. Your try_collection_for_each (branch line 657) is a duplicate that now has no caller. Take main's call and delete try_collection_for_each — that also fixes violation (a) below, so don't skip the delete.

2. perry-stdlib/src/fetch/request_ctor.rs — genuinely combine.
Different concerns, both needed. main added a Blob/File guard (#6231): a Blob body is a handle-band id, not a real pointer, so it must be resolved from the blob registry before anything dereferences it — body_bytes_from_header on a handle-band id segfaults. Your stream-id path is orthogonal. Order matters — handle-band check first:

let body: Option<Vec<u8>> =
    if perry_runtime::value::addr_class::is_handle_band(body_ptr as usize) {
        crate::fetch::blob_bytes_clone(body_ptr as usize)
    } else {
        take_pending_fetch_body_stream_id()
            .map(crate::streams::drain_readable_into_bytes)
            .or_else(|| dispatch::body_addr_buffer_bytes(body_ptr as usize))
            .or_else(|| dispatch::body_bytes_from_header(body_ptr))
    };

3. perry-stdlib/src/streams/subclass.rs — take main's side.
Doc-comment only, but the code under it was rewritten: drain_readable_into_bytes now drives pull (collect queued → maybe_pull → run microtasks → repeat) instead of snapshotting whatever was already queued and force-closing. Your old version dropped anything produced by a pull callback. This should help TanStack SSR streams rather than hurt them — same bug class that broke axios's trackStream.

File-size cap (2000 lines) — the lint failure

(a) array/generic.rs → 2033. Deleting the dead try_collection_for_each per conflict 1 puts it back under (main is at 1998).

(b) perry-codegen/src/lower_call/extern_func.rs → 2003. This one needs a real trim: main has already pushed that file to 1999, so there is exactly one line of headroom and your change adds ~4. Extracting a coherent group into a sibling module (re-exported from mod.rs with explicit use — globs don't propagate through transitive re-exports) is the sanctioned recipe.

Happy to take the rebase on if you'd prefer — I held off because conflict 2 and the extern_func.rs split are judgment calls inside your change, and I can't run TanStack Start end-to-end here to confirm I preserved your semantics.

@TheHypnoo TheHypnoo added bug Confirmed defect or regression parity Compatibility gap with Node.js, ECMAScript, or the supported ecosystem labels Jul 26, 2026
@proggeramlug
proggeramlug force-pushed the feat/tanstack-start-compat branch from 96d9e03 to c76e6d9 Compare August 1, 2026 11:45
@proggeramlug
proggeramlug marked this pull request as ready for review August 1, 2026 11:45
@proggeramlug
proggeramlug merged commit 9ab10d9 into main Aug 1, 2026
25 of 38 checks passed
@proggeramlug
proggeramlug deleted the feat/tanstack-start-compat branch August 1, 2026 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Confirmed defect or regression parity Compatibility gap with Node.js, ECMAScript, or the supported ecosystem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants