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
10 changes: 9 additions & 1 deletion .github/workflows/pullrequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,15 @@ jobs:
run: npm ci

- name: Build Wasm Bindgen
run: cd wasm-bindgen && cargo build -p wasm-bindgen-cli --bin wasm-bindgen
run: cd wasm-bindgen && cargo build -p wasm-bindgen-cli --bin wasm-bindgen --bin wasm-bindgen-test-runner

- name: Install wasm32 target
run: rustup target add wasm32-unknown-unknown

- name: Run wasm-bindgen tests
env:
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER: ${{ github.workspace }}/wasm-bindgen/target/debug/wasm-bindgen-test-runner
run: cargo test -p worker --target wasm32-unknown-unknown

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions worker-sys/src/types/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ extern "C" {

#[wasm_bindgen(method, catch, js_name=passThroughOnException)]
pub fn pass_through_on_exception(this: &Context) -> Result<(), JsValue>;

#[wasm_bindgen(method, getter)]
pub fn props(this: &Context) -> JsValue;
}
3 changes: 3 additions & 0 deletions worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ d1 = ["worker-sys/d1"]
http = ["worker-macros/http"]
axum = ["dep:axum"]
timezone = ["dep:chrono-tz"]

[dev-dependencies]
wasm-bindgen-test.workspace = true
95 changes: 95 additions & 0 deletions worker/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::future::Future;

use crate::worker_sys::Context as JsContext;
use crate::Result;

use serde::de::DeserializeOwned;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::future_to_promise;

Expand Down Expand Up @@ -47,10 +49,103 @@ impl Context {
pub fn pass_through_on_exception(&self) {
self.inner.pass_through_on_exception().unwrap()
}

/// Get the props passed to this worker execution context.
///
/// Props provide a way to pass additional configuration to a worker based on the context
/// in which it was invoked. For example, when your Worker is called by another Worker via
/// a Service Binding, props can provide information about the calling worker.
///
/// Props are configured in your wrangler.toml when setting up Service Bindings:
/// ```toml
/// [[services]]
/// binding = "MY_SERVICE"
/// service = "my-worker"
/// props = { clientId = "frontend", permissions = ["read", "write"] }
/// ```
///
/// Then deserialize them to your custom type:
/// ```no_run
/// use serde::Deserialize;
///
/// #[derive(Deserialize)]
/// struct MyProps {
/// clientId: String,
/// permissions: Vec<String>,
/// }
///
/// let props = ctx.props::<MyProps>()?;
/// ```
///
/// See: <https://developers.cloudflare.com/workers/runtime-apis/context/#props>
pub fn props<T: DeserializeOwned>(&self) -> Result<T> {
Ok(serde_wasm_bindgen::from_value(self.inner.props())?)
}
}

impl AsRef<JsContext> for Context {
fn as_ref(&self) -> &JsContext {
&self.inner
}
}

#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
use wasm_bindgen::JsCast;
use wasm_bindgen_test::*;

#[derive(Debug, Deserialize, PartialEq)]
struct TestProps {
#[serde(rename = "clientId")]
client_id: String,
permissions: Vec<String>,
}

#[wasm_bindgen_test]
fn test_props_deserialization() {
// Create a mock ExecutionContext with props
let obj = js_sys::Object::new();

// Add props to the object
let props = js_sys::Object::new();
js_sys::Reflect::set(&props, &"clientId".into(), &"frontend-worker".into()).unwrap();

let permissions = js_sys::Array::new();
permissions.push(&"read".into());
permissions.push(&"write".into());
js_sys::Reflect::set(&props, &"permissions".into(), &permissions.into()).unwrap();

js_sys::Reflect::set(&obj, &"props".into(), &props.into()).unwrap();

// Create a Context from the mock object
let js_context: JsContext = obj.unchecked_into();
let context = Context::new(js_context);

// Test that props can be deserialized
let result: Result<TestProps> = context.props();
assert!(result.is_ok());

let props = result.unwrap();
assert_eq!(props.client_id, "frontend-worker");
assert_eq!(props.permissions, vec!["read", "write"]);
}

#[wasm_bindgen_test]
fn test_props_empty_object() {
// Create a mock ExecutionContext with empty props
let obj = js_sys::Object::new();
let props = js_sys::Object::new();
js_sys::Reflect::set(&obj, &"props".into(), &props.into()).unwrap();

let js_context: JsContext = obj.unchecked_into();
let context = Context::new(js_context);

#[derive(Debug, Deserialize, PartialEq)]
struct EmptyProps {}

let result: Result<EmptyProps> = context.props();
assert!(result.is_ok());
}
}