pierrejeambrun opened a new pull request, #73723:
URL: https://github.com/apache/airflow/pull/73723
A bundle whose native Dags live in more than one file only carried its
entrypoint's source in the `airflowSource` region. Airflow's Code tab
would show the entrypoint for every Dag: the file for the ones declared
there, and something unrelated for the ones declared in imported
modules. Multi-Dag bundles were effectively single-source in the UI.
## What changes
- **Each Dag's source file is embedded**, one per unique path. The
bundle header's single `source` region becomes `sources: [{path,
start, end, sha256}]`. Each region has its own `/*# airflowSource:<path> …
#*/` block comment so the path is visible in the raw bundle too.
- **Metadata gains `dag_source_paths: Record<dag_id, path>`** so a
reader can pick the right source per Dag without guessing.
- **`Dag`'s constructor records which file it ran in**. It reads a
cross-realm global slot
(`Symbol.for("airflow.ts-sdk.current-module-source")`)
that `airflow-ts-pack`'s new onLoad plugin writes at the top of each
author-owned source file. ES module hoisting is what makes the slot
the current file for every top-level `new Dag(...)` call, so the
constructor just reads it. `Function.prototype.toString` and stack
parsing stay out. Same `Symbol.for` pattern the SDK already uses for
the task-scope AsyncLocalStorage.
- **Files that only supply utilities or types are not embedded.** Only
the files whose `new Dag(...)` constructor ran end up in the source
regions — matches Python's `dag.fileloc` behavior.
- **Mixed-language bundles** (Python owns the Dag, TS supplies handlers)
carry no source regions; `dag_source_paths` is empty. Their Python
side is what displays in the UI.
## Reproducing before/after
```
src/main.ts # declares `orders_dag`, imports and registers
reports_dag
src/dags/reports.ts # declares `reports_dag`
```
Before: bundle carries only `main.ts` in the source region; `reports_dag`
has no source for the Code tab.
After: bundle carries both files as separate regions; metadata has
`dag_source_paths: {orders_dag: "src/main.ts", reports_dag:
"src/dags/reports.ts"}`.
Verified end-to-end on a pack of that layout — both files land in the
header's `sources` list with their own byte ranges and digests.
## Test coverage
- `buildBundleManifest` records paths from the module-source slot.
- Encoder: one region per file, path-tagged marker, empty case (no
sources) for pure mixed-lang bundles.
- Pack: multi-Dag bundle where two files declare Dags across an import
boundary — asserts both sources are embedded and `dag_source_paths`
maps each `dag_id` to its file.
- Existing shebang test still passes: the plugin's slot-write goes
after the shebang line so `#!/usr/bin/env node` stays valid.
## Not in scope
- Server-side importer for `.min.mjs` bundles is future work; nothing
reads `dag_source_paths` yet on the Airflow side. This PR only fixes
the pack-time embedding shape so the data is present when the
importer lands.
---
##### Was generative AI tooling used to co-author this PR?
- [X] Yes — Claude Code (Opus 4.7)
Generated-by: Claude Code (Opus 4.7) following [the
guidelines](https://github.com/apache/airflow/blob/main/contributing-docs/05_pull_requests.rst#gen-ai-assisted-contributions)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]