Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ members = [
"worker-sys",
"worker-kv",
"examples/*",
"test/container-echo",
"test/container-echo"
]
exclude = ["examples/coredump", "examples/axum", "templates/*", "wasm-bindgen"]
resolver = "2"
Expand All @@ -20,17 +20,22 @@ chrono = { version = "0.4.41", default-features = false, features = [
futures-channel = "0.3.31"
futures-util = { version = "0.3.31", default-features = false }
http = "1.3"
js-sys = { version = "0.3.78", path = "./wasm-bindgen/crates/js-sys" }
js-sys = { version = "0.3.80", path = "./wasm-bindgen/crates/js-sys" }
serde = { version = "1.0.164", features = ["derive"] }
serde_json = "1.0.140"
serde-wasm-bindgen = "0.6.5"
wasm-bindgen = { version = "0.2.103", path = "./wasm-bindgen" }
wasm-bindgen-cli-support = { version = "0.2.103", path = "./wasm-bindgen/crates/cli-support" }
wasm-bindgen-futures = { version = "0.4.51", path = "./wasm-bindgen/crates/futures" }
wasm-bindgen-futures = { version = "0.4.53", path = "./wasm-bindgen/crates/futures" }
wasm-bindgen-macro-support = { version = "0.2.103", path = "./wasm-bindgen/crates/macro-support" }
wasm-bindgen-shared = { version = "0.2.103", path = "./wasm-bindgen/crates/shared" }
wasm-bindgen-test = { version = "0.3.51", path = "./wasm-bindgen/crates/test" }
web-sys = { version = "0.3.79", path = "./wasm-bindgen/crates/web-sys" }
web-sys = { version = "0.3.80", features = [
"File",
"ReadableStreamDefaultReader",
"WorkerGlobalScope",
"WritableStreamDefaultWriter",
] }
worker = { path = "worker", version = "0.6.5", features = ["queue", "d1", "axum", "timezone"] }
worker-codegen = { path = "worker-codegen", version = "0.2.0" }
worker-kv = { path = "worker-kv", version = "0.9.0" }
Expand Down Expand Up @@ -61,11 +66,11 @@ codegen-units = 1
opt-level = "z"

[patch.crates-io]
js-sys = { version = "0.3.79", path = './wasm-bindgen/crates/js-sys' }
js-sys = { version = "0.3.80", path = './wasm-bindgen/crates/js-sys' }
wasm-bindgen = { version = "0.2.103", path = './wasm-bindgen' }
wasm-bindgen-cli-support = { version = "0.2.103", path = "./wasm-bindgen/crates/cli-support" }
wasm-bindgen-futures = { version = "0.4.51", path = './wasm-bindgen/crates/futures' }
wasm-bindgen-futures = { version = "0.4.53", path = './wasm-bindgen/crates/futures' }
wasm-bindgen-macro-support = { version = "0.2.103", path = "./wasm-bindgen/crates/macro-support" }
wasm-bindgen-shared = { version = "0.2.103", path = "./wasm-bindgen/crates/shared" }
wasm-bindgen-test = { version = "0.3.51", path = "./wasm-bindgen/crates/test" }
web-sys = { version = "0.3.79", path = './wasm-bindgen/crates/web-sys' }
web-sys = { version = "0.3.80", path = './wasm-bindgen/crates/web-sys' }
583 changes: 301 additions & 282 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@
"homepage": "https://github.com/cloudflare/workers-rs#readme",
"devDependencies": {
"@types/node": "^24.0.1",
"miniflare": "^4.20250823.0",
"miniflare": "^4.20250923.0",
"typescript": "^5.8.3",
"undici": "^7.12.0",
"undici": "7.14.0",
"uuid": "^11.1.0",
"vitest": "^3.2.4"
},
"scripts": {
"build": "cd wasm-bindgen && cargo build -p wasm-bindgen-cli --bin wasm-bindgen && cd .. && cargo build -p worker-build",
"test": "cd test && NO_MINIFY=1 WASM_BINDGEN_PATH=../wasm-bindgen/target/debug/wasm-bindgen ../target/debug/worker-build --dev && NODE_OPTIONS='--experimental-vm-modules' npx vitest run",
"test-http": "cd test && NO_MINIFY=1 WASM_BINDGEN_PATH=../wasm-bindgen/target/debug/wasm-bindgen ../target/debug/worker-build --release --features http && NODE_OPTIONS='--experimental-vm-modules' npx vitest run",
"test-mem": "cd test && npx wrangler dev --enable-containers=false",
"lint": "cargo clippy --features d1,queue --all-targets --workspace -- -D warnings",
"lint:fix": "cargo fmt && cargo clippy --features d1,queue --all-targets --workspace --fix -- -D warnings"
}
Expand Down
24 changes: 11 additions & 13 deletions test/src/alarm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,34 @@ use super::SomeSharedData;
#[durable_object]
pub struct AlarmObject {
state: State,
// used for memory leak detection
_buffer: Vec<u8>,
}

impl DurableObject for AlarmObject {
fn new(state: State, _: Env) -> Self {
Self { state }
Self {
state,
_buffer: Vec::with_capacity(111_000_000),
}
}

async fn fetch(&self, _: Request) -> Result<Response> {
self.state
.storage()
.set_alarm(Duration::from_millis(100))
.await?;
let alarmed: bool = match self.state.storage().get("alarmed").await {
Ok(alarmed) => alarmed,
Err(e) if e.to_string() == "No such value in storage." => {
// Trigger our alarm method in 100ms.
self.state
.storage()
.set_alarm(Duration::from_millis(100))
.await?;

false
}
Err(e) if e.to_string() == "No such value in storage." => false,
Err(e) => return Err(e),
};

Response::ok(alarmed.to_string())
}

async fn alarm(&self) -> Result<Response> {
self.state.storage().put("alarmed", true).await?;

console_log!("Alarm has been triggered!");

Response::ok("ALARMED")
}
}
Expand Down
5 changes: 2 additions & 3 deletions test/wrangler.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name = "testing-rust-worker"
workers_dev = true
compatibility_date = "2022-09-12" # required
compatibility_flags = ["streams_enable_constructors"]
compatibility_date = "2025-09-23" # required
main = "build/worker/shim.mjs"

kv_namespaces = [
Expand Down Expand Up @@ -70,7 +69,7 @@ bucket_name = 'delete-bucket'
preview_bucket_name = 'delete-bucket'

[build]
command = "../target/debug/worker-build --release"
command = "WASM_BINDGEN_PATH=../wasm-bindgen/target/debug/wasm-bindgen ../target/debug/worker-build --release"

[[migrations]]
tag = "v1"
Expand Down
42 changes: 12 additions & 30 deletions worker-build/src/js/shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { WorkerEntrypoint } from "cloudflare:workers";
import * as exports from "./index.js";
export * from "./index.js";

let panicError = null;
Error.stackTraceLimit = 100;

let panicError = null;
function registerPanicHook() {
exports.setPanicHook(function (message) {
panicError = new Error("Critical Rust panic: " + message);
Expand All @@ -14,55 +14,37 @@ function registerPanicHook() {

registerPanicHook();

let instanceId = 0;
function checkReinitialize() {
if (panicError) {
console.log("Reinitializing Wasm application");
exports.__wbg_reset_state();
panicError = null;
registerPanicHook();
for (const instance of instances) {
const newInstance = Reflect.construct(instance.target, instance.args, instance.newTarget);
instance.instance = newInstance;
}
instanceId++;
}
}

export default class Entrypoint extends WorkerEntrypoint {
async fetch(request) {
checkReinitialize();
let response = exports.fetch(request, this.env, this.ctx);
$WAIT_UNTIL_RESPONSE;
return await response;
}

async queue(batch) {
checkReinitialize();
return await exports.queue(batch, this.env, this.ctx);
}

async scheduled(event) {
checkReinitialize();
return await exports.scheduled(event, this.env, this.ctx);
}
$HANDLERS
}

const instances = [];
const classProxyHooks = {
construct(target, args, newTarget) {
construct(ctor, args, newTarget) {
const instance = {
instance: Reflect.construct(target, args, newTarget),
target,
instance: Reflect.construct(ctor, args, newTarget),
instanceId,
ctor,
args,
newTarget
};
instances.push(instance);
return new Proxy(instance, {
get(target, prop, receiver) {
if (target.instanceId !== instanceId) {
target.instance = Reflect.construct(target.ctor, target.args, target.newTarget);
target.instanceId = instanceId;
}
return Reflect.get(target.instance, prop, receiver);
},

set(target, prop, value, receiver) {
return Reflect.set(target.instance, prop, value, receiver);
}
});
}
Expand Down
72 changes: 63 additions & 9 deletions worker-build/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,8 @@ pub fn main() -> Result<()> {
}

if supports_module_and_reset_state {
update_package_json()?;

let esbuild_path = install::ensure_esbuild()?;
let (has_fetch_handler, has_queue_handler, has_scheduled_handler) =
detect_exported_handlers()?;

let shim_template = match env::var("CUSTOM_SHIM") {
Ok(path) => {
Expand All @@ -106,20 +105,49 @@ pub fn main() -> Result<()> {
Err(_) => SHIM_FILE.to_owned(),
};

let wait_until_response = if env::var("RUN_TO_COMPLETION").is_ok() {
"this.ctx.waitUntil(response);"
} else {
""
};
let mut handlers = String::new();
if has_fetch_handler {
let wait_until_response = if env::var("RUN_TO_COMPLETION").is_ok() {
"this.ctx.waitUntil(response);"
} else {
""
};
handlers += &format!(
" async fetch(request) {{
checkReinitialize();
let response = exports.fetch(request, this.env, this.ctx);
{wait_until_response}
return await response;
}}
"
)
}
if has_queue_handler {
handlers += " async queue(batch) {
checkReinitialize();
return await exports.queue(batch, this.env, this.ctx);
}
"
}
if has_scheduled_handler {
handlers += " async scheduled(event) {
checkReinitialize();
return await exports.scheduled(event, this.env, this.ctx);
}
"
}

let shim = shim_template.replace("$WAIT_UNTIL_RESPONSE", wait_until_response);
let shim = shim_template.replace("$HANDLERS", &handlers);

fs::write(output_path("shim.js"), shim)?;

fix_heap_assignment()?;

add_exported_class_wrappers(detect_exported_class_names()?)?;

update_package_json()?;

let esbuild_path = install::ensure_esbuild()?;
bundle(&esbuild_path)?;

fix_wasm_import()?;
Expand All @@ -135,6 +163,32 @@ pub fn main() -> Result<()> {
Ok(())
}

fn detect_exported_handlers() -> Result<(bool, bool, bool)> {
let index_path = output_path("index.js");
let content = fs::read_to_string(&index_path)?;

let mut has_fetch_handler = false;
let mut has_queue_handler = false;
let mut has_scheduled_handler = false;
for line in content.lines() {
if !line.contains("export function") {
continue;
}
if let Some(rest) = line.strip_prefix("export function") {
if let Some(bracket_pos) = rest.find("(") {
let func_name = rest[..bracket_pos].trim();
match func_name {
"fetch" => has_fetch_handler = true,
"queue" => has_queue_handler = true,
"scheduled" => has_scheduled_handler = true,
_ => {}
}
}
}
}
Ok((has_fetch_handler, has_queue_handler, has_scheduled_handler))
}

fn detect_exported_class_names() -> Result<Vec<String>> {
let index_path = output_path("index.js");
let content = fs::read_to_string(&index_path)?;
Expand Down
7 changes: 1 addition & 6 deletions worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ worker-kv.workspace = true
worker-macros.workspace = true
worker-sys.workspace = true
chrono-tz = { version = "0.10.3", optional = true, default-features = false }
web-sys = { version = "0.3.70", features = [
"File",
"WorkerGlobalScope",
"ReadableStreamDefaultReader",
"WritableStreamDefaultWriter",
] }
web-sys.workspace = true
tokio-postgres = { version = "0.7", optional = true, default-features = false, features = [
"js",
] }
Expand Down