Living Standard — Last Updated 2 October 2025
TODO: introduction, what's all this?
partial interface Element {
WritableStream patchUnsafe(optional PatchUnsafeOptions options = {});
};
partial interface ShadowRoot {
WritableStream patchUnsafe(optional PatchUnsafeOptions options = {});
};
dictionary PatchUnsafeOptions {
boolean runScripts = false;
};
Element
's patchUnsafe(options)
method steps
are:
Let writable be a new WritableStream.
👋 Sketch of the streams setup:
Incoming chunks must all be of the same type, either strings, bytes, or a trusted types wrapper.
Some decisions are made based on the first chunk:
If it's not a trusted types wrapper and there is a default TT policy, create a
transform stream using createTransformStream
from the default policy.
Then pipe chunks through that transform stream.
If it's bytes, create an UTF-8 TextDecoderStream and pipe chunks through that.
TODO: which should happen first? should we allow the TT transform stream to take bytes as input, or guarantee that it's strings by then?
As chunks are coming through, before handing them to the parser, check that they're all of the same type. For trusted types, also check that the chunks are in the same order and not duplicated/filtered/reordered.
👋 Sketch of the parser setup:
Let parser be a new fragment parser.
Add this to the stack of open elements.
If options["runScripts
"],
don't mark scripts as already executed.
Write chunks into the parser as they are written to writable.
When a template
element with a patchfor
attribute
comes out of the parser, find the target node by ID and set that as the parser's insertion
point.
The first time an element is patched, replace all children. Subsequent patches to the same target append children.
Return writable.
Do a thing like this:
const policy = trustedTypes.createPolicy("my-policy", {
createTransformStream() {
return new TransformStream({
transform(chunk, controller) {
// TODO: some buffering
controller.enqueue(sanitize(chunk));
}
});
}
});
const response = await fetch('/fragments/something');
const transform = policy.createTransformStream();
const writable = element.patchUnsafe();
await response.body.pipeThrough(transform).pipeTo(writable);
ShadowRoot
's patchUnsafe(options)
method steps
are: