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
6 changes: 3 additions & 3 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ dioxus = { version = "=0.7.10", default-features = false, features = ["macro", "
# docs/design.md "Pins, with reasons": unpublished, moving; policy object
# and asset handles landed in #15. Full 40-char sha of origin/main at the
# time this skeleton was cut.
stream-dom-dioxus = { git = "https://github.com/polymorph-components/polymorph-stream-dom", rev = "197492374936b3b4ce5af55f2bac50fa6b551597" }
stream-dom-guest = { git = "https://github.com/polymorph-components/polymorph-stream-dom", rev = "197492374936b3b4ce5af55f2bac50fa6b551597" }
stream-dom-dioxus = { git = "https://github.com/polymorph-components/polymorph-stream-dom", rev = "e35dc357137a3563aa891662a626b3310a7078c4" }
stream-dom-guest = { git = "https://github.com/polymorph-components/polymorph-stream-dom", rev = "e35dc357137a3563aa891662a626b3310a7078c4" }
# The store's name derivation (docs/design.md "Storage", internal.wit
# `storage`): every object in the user's Drive is named
# `hex(HMAC-SHA256(name-key, tree || commit))`, so two devices of a group
Expand Down
48 changes: 33 additions & 15 deletions apps/todomvc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ enum FilterState {
Completed,
}

/// The stylesheet's asset handle, `asset:` followed by `manifest.json`'s
/// `handle` for `todomvc-app.css` — the spelling upstream's writer gives an
/// asset-valued attribute (polymorph-stream-dom#19, `writer.rs` `asset_handle`). The
/// `tests` module below asserts these stay in agreement.
const STYLESHEET: &str = "asset:0f827d119b7bec30534b1767e8ab8ee0f2890c98f93baa1159dcf1a46f10bc17";

pub fn app() -> Element {
// The snapshot. Owned by the `tasks` service; this is a cached view of it.
let items = use_signal(Vec::<TodoItem>::new);
Expand Down Expand Up @@ -249,17 +255,8 @@ pub fn app() -> Element {
};

rsx! {
// CONTRACT: the stylesheet link is deliberately absent. The app should
// emit `link { rel: "stylesheet", href: <asset handle> }` using
// `stream_dom_guest::Batch::set_attribute_asset`, but Dioxus attribute
// values are strings and `stream-dom-dioxus`'s writer has no
// convention for spelling an asset handle as one: its `set_attribute`
// (crates/stream-dom-dioxus/src/writer.rs:540) reduces every value
// through `serialize` to text and only ever calls
// `Batch::set_attribute` / `set_property` — the string `asset` does
// not appear anywhere in that file. So there is no way for this crate
// to reach `set_attribute_asset` today; the change belongs in
// `writer.rs:540`, upstream. M1's gate is functional, not pretty.
link { rel: "stylesheet", href: STYLESHEET }

section { class: "todoapp",
TodoHeader { items }
section { class: "main",
Expand Down Expand Up @@ -485,15 +482,18 @@ fn ListFooter(
/// handles"). Nothing else checks that at build time, so this does.
#[cfg(test)]
mod tests {
use super::STYLESHEET;
use sha2::{Digest, Sha256};

fn manifest() -> serde_json::Value {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
serde_json::from_str(&std::fs::read_to_string(dir.join("manifest.json")).unwrap()).unwrap()
}

#[test]
fn manifest_asset_handles_match_the_bytes() {
let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let manifest: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(dir.join("manifest.json")).unwrap())
.unwrap();

let manifest = manifest();
let assets = manifest["assets"].as_array().unwrap();
assert!(!assets.is_empty(), "manifest declares no assets");

Expand All @@ -508,4 +508,22 @@ mod tests {
);
}
}

/// The app's `STYLESHEET` const must name the same asset the manifest
/// declares for `todomvc-app.css`, in the `asset:<hex>` spelling
/// upstream's writer expects (polymorph-stream-dom#19).
#[test]
fn stylesheet_const_matches_the_manifest_handle() {
let manifest = manifest();
let assets = manifest["assets"].as_array().unwrap();
let css = assets
.iter()
.find(|a| a["path"].as_str() == Some("todomvc-app.css"))
.expect("manifest declares no todomvc-app.css asset");
let expected = format!("asset:{}", css["handle"].as_str().unwrap());
assert_eq!(
STYLESHEET, expected,
"STYLESHEET is stale against manifest.json"
);
}
}
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@remote-dom/core": "npm:@remote-dom/core@^1.11.1",
"@remote-dom/core/receivers": "npm:@remote-dom/core@^1.11.1/receivers",
"@remote-dom/core/elements": "npm:@remote-dom/core@^1.11.1/elements",
"@polymorph/stream-dom-receiver/": "https://raw.githubusercontent.com/polymorph-components/polymorph-stream-dom/197492374936b3b4ce5af55f2bac50fa6b551597/receiver/src/",
"@polymorph/stream-dom-receiver/": "https://raw.githubusercontent.com/polymorph-components/polymorph-stream-dom/e35dc357137a3563aa891662a626b3310a7078c4/receiver/src/",
"@std/assert": "jsr:@std/assert@^1",
"playwright": "npm:playwright@1.62.1",
"@std/fs": "jsr:@std/fs@^1",
Expand Down
25 changes: 13 additions & 12 deletions deno.lock

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

2 changes: 1 addition & 1 deletion docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ native tests, so browser gates are mandatory for every visor change.
| `wit-bindgen` | `=0.60.0`, workspace-wide | must equal stream-dom's pin: `StreamReader<u8>` (a wit-bindgen runtime type) crosses the delegation from our world's `run` into `stream_dom_dioxus::driver::run`. Different wit-bindgen versions *can* coexist in one component (the `wasip3_task_set` weak-symbol ABI exists for exactly that), but not across a shared runtime type. Bumps follow stream-dom's. `generate!` never sets `async: true`: that lowers sync WIT functions (resource constructors) async, which the canonical ABI forbids and only the translator catches; WIT's own `async func` annotations are the source of truth |
| `@polyengine/*` | 0.6.7, one version across the graph | first release where an async export may park on a guest waker (#292) without the 0.6.6 lift regression (#312); brand symbols are per-version, so a partial upgrade fails at `instanceof` |
| `dioxus` | `=0.7.10` | dioxus-core state is shared with `stream-dom-dioxus`; skew breaks the build |
| polymorph-stream-dom | git rev (see Cargo.toml / deno.json) | unpublished, moving; policy object and asset handles landed in #15 |
| polymorph-stream-dom | git rev (see Cargo.toml / deno.json) | unpublished, moving; policy object and asset handles landed in #15; the Dioxus `asset:<hex>` attribute spelling landed in #19 |
| subduction | git `sansio` rev | above |
| keyhive | git rev `a509a2d` | `keyhive_core` / `keyhive_crypto` / `beekem`, unreleased and moving. The sealed plaintext is keyhive's own `Envelope` and the read-back walk is keyhive's own `try_causal_decrypt`, so a rev bump is a wire-format change for every stored blob: its own PR |
| `@polymorph/*` | 0.6.1 (webcrypto, websocket), 0.6.2 (webrtc-datachannels) | the cuts current at the polyengine 0.6.7 pin; taken within the `^0.6` range |
Expand Down
20 changes: 14 additions & 6 deletions e2e/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1189,15 +1189,23 @@ const scenarios: Scenario[] = [
await launchTodoMvc(page);
await page.frameLocator("#app-zone iframe").locator("input").first()
.waitFor({ timeout: 30_000 });
// The app emits no `<link>` in M1 (apps/todomvc/src/lib.rs's CONTRACT
// note), and the frame's CSP has no connect-src at all: there is
// nothing the frame could fetch even if it named something.
// The app's one fetch is its stylesheet, a `blob:` URL the frame
// minted from the bundle (web/frame.ts's `resolveAsset`) — Playwright
// reports it as a request but it is not network. The frame's CSP has
// no connect-src at all, so nothing else can leave.
const notBlob = fromFrame.filter((url) => !url.startsWith("blob:"));
check(
fromFrame.length === 0,
`the app frame made ${fromFrame.length} request(s): ${
fromFrame.join(", ")
notBlob.length === 0,
`the app frame made ${notBlob.length} non-blob request(s): ${
notBlob.join(", ")
}`,
);

// The stylesheet did apply: `.todoapp { background: #fff }` from
// apps/todomvc/assets/todomvc-app.css.
const background = await todoFrame(page).locator("section.todoapp")
.evaluate((el) => getComputedStyle(el).backgroundColor);
eq(background, "rgb(255, 255, 255)", "the stylesheet did not apply");
},
},

Expand Down
Loading