Overview
opendev simulate accepts more than just base64 blobs — it can execute scripts that build transactions and pipe the output into the simulation pipeline.
Accepted inputs
Protocol
Your script must print the base64-serialized transaction on stdout. The runner picks the last non-empty stdout line that matches the base64 alphabet and is at least 100 characters long. Everything else is ignored — logs, debug output, warnings, etc. — as long as it isn’t the final line.Example output
TypeScript
Top-level await (.mts)
The fastest path. The .mts extension forces ESM regardless of package.json:
Plain .ts with async wrapper
If you prefer .ts over .mts (to avoid confusion in your project), wrap the body:
Why wrap in
main()?
tsx detects ESM vs CJS by walking up to the nearest package.json. If that file lacks "type": "module", tsx emits CJS — and CJS doesn’t support top-level await. Wrapping avoids this issue without modifying your project’s package.json.Rust
Cargo.toml setup
src/main.rs
JavaScript
Standard Node.js —await works without wrappers:
Common pitfalls
TypeScript top-level await caveat
tsx decides between CJS and ESM by checking the nearest package.json. If it lacks "type": "module", tsx emits CJS — and CJS doesn’t support top-level await.
Three solutions (pick one):
-
Rename to
.mts(forces ESM): -
Add
"type": "module"topackage.json(affects your entire project): -
Wrap in
main()(recommended for most projects):
WSL node_modules mismatch
If your repo lives on/mnt/c/... and you switch between Windows and WSL, the node_modules installed under one OS won’t work under the other. esbuild’s native binary is OS-specific.
Error: esbuild was installed for a different platform
Quick fix:
~/dev/...) in WSL — also 10–50× faster I/O.
Safety
opendev simulate shows a yellow EXECUTING USER CODE banner before running any script. This is intentional — source files can execute arbitrary code.
CI/safety mode
--no-exec, the command fails rather than executing.