diff --git a/CHANGELOG.md b/CHANGELOG.md
index e0b7d77..9bfc820 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# 1.1.1
+
+Released on Wednesday, October 7 2026.
+
+- Fixed background thread leaks when worker construction is rejected (#143) @PrzemyslawKlys
+- Fixed canonical DOM node identity and concrete prototypes through `DomSameObject` getters (#141) @PrzemyslawKlys
+- Added `JsScriptingOptions.EngineCreator` to create a configured Jint engine before any page script runs (#142) @PrzemyslawKlys
+
# 1.1.0
Released on Saturday, September 5 2026.
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 4583bc6..6db8b7d 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -13,6 +13,7 @@ AngleSharp.Js contains code written by (in order of first pull request / commit)
* [Marko Lahma](https://github.com/lahma)
* [Bogdan Maltcev](https://github.com/badnickname)
* [arekdygas](https://github.com/arekdygas)
+* [Przemysław Kłys](https://github.com/PrzemyslawKlys)
Without these awesome people AngleSharp.Js could not exist. Thanks to everyone for your contributions! :beers:
diff --git a/README.md b/README.md
index 4bcaac2..e08377a 100644
--- a/README.md
+++ b/README.md
@@ -46,6 +46,29 @@ var config = Configuration.Default
});
```
+Register an `EngineCreator` service to configure Jint before inline page scripts run:
+
+```cs
+using Jint;
+using AngleSharp.Js;
+
+var config = Configuration.Default
+ .With(new EngineCreator((window, options) => new Engine(options
+ .MaxStatements(100_000)
+ .TimeoutInterval(TimeSpan.FromSeconds(5))
+ .LimitMemory(16 * 1024 * 1024))))
+ .WithJs();
+```
+
+The factory runs once for each window and must return a fresh engine using the supplied options.
+Those options contain AngleSharp's DOM module loader, object wrapper, and call stack guard.
+DOM bindings are installed after the factory returns. Configure the engine and host globals
+in the factory, then access DOM objects and evaluate page scripts through the document.
+Jint controls the scope and reset behavior of its constraints.
+Any state captured by the service remains owned by the host.
+Hosts sharing one configuration across windows must make
+their captured state safe for that use.
+
You can also use this part with a console for logging. The call for this is `WithConsoleLogger`, e.g.,
```cs
diff --git a/src/AngleSharp.Js.Docs/package.json b/src/AngleSharp.Js.Docs/package.json
index 7e7e7c4..b7ca4a5 100644
--- a/src/AngleSharp.Js.Docs/package.json
+++ b/src/AngleSharp.Js.Docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@anglesharp/js",
- "version": "1.1.0",
+ "version": "1.1.1",
"preview": true,
"description": "The doclet for the AngleSharp.Js documentation.",
"keywords": [
diff --git a/src/AngleSharp.Js.Tests/EngineConfigurationTests.cs b/src/AngleSharp.Js.Tests/EngineConfigurationTests.cs
new file mode 100644
index 0000000..cc69a88
--- /dev/null
+++ b/src/AngleSharp.Js.Tests/EngineConfigurationTests.cs
@@ -0,0 +1,165 @@
+namespace AngleSharp.Js.Tests
+{
+ using AngleSharp.Dom;
+ using AngleSharp.Io;
+ using AngleSharp.Js.Tests.Mocks;
+ using AngleSharp.Scripting;
+ using Jint;
+ using Jint.Runtime;
+ using NUnit.Framework;
+ using System;
+ using System.Collections.Concurrent;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ public class EngineConfigurationTests
+ {
+ [Test]
+ public async Task ConstraintsAreInstalledBeforeInlineScriptsRun()
+ {
+ var config = Configuration.Default
+ .With(new EngineCreator((window, options) => new Engine(options.MaxStatements(64))))
+ .WithJs()
+ .WithEventLoop();
+
+ using (var context = BrowsingContext.New(config))
+ {
+ var document = await context.OpenAsync(request => request.Content(
+ "
before
")).ConfigureAwait(false);
+
+ Assert.AreEqual("before", document.QuerySelector("#result").TextContent);
+ Assert.Throws(() => document.ExecuteScript(
+ "for (var i = 0; i < 1000; i++) {}"));
+ Assert.AreEqual("before", document.ExecuteScript("document.getElementById('result').textContent"));
+ }
+ }
+
+ [Test]
+ public async Task CreatorServiceCanBeCreatedForEachBrowsingContext()
+ {
+ var services = 0;
+ Func createService = _ =>
+ {
+ services++;
+ var limit = services == 1 ? 64 : 2000;
+ return (window, options) => new Engine(options.MaxStatements(limit));
+ };
+ var config = Configuration.Default.With(createService).WithJs().WithEventLoop();
+
+ using (var first = BrowsingContext.New(config))
+ using (var second = BrowsingContext.New(config))
+ {
+ var firstDocument = await first.OpenNewAsync().ConfigureAwait(false);
+ var secondDocument = await second.OpenNewAsync().ConfigureAwait(false);
+ Assert.Throws(() => firstDocument.ExecuteScript(
+ "for (var i = 0; i < 1000; i++) {}"));
+ Assert.AreEqual(100, secondDocument.ExecuteScript("var i = 0; for (; i < 100; i++) {} i;"));
+ Assert.AreEqual(2, services);
+ }
+ }
+
+ [Test]
+ public async Task CreatorRunsOncePerWindowAndRetainsDomWrapping()
+ {
+ var calls = 0;
+ var windows = new ConcurrentQueue();
+ var config = Configuration.Default.With(new EngineCreator((window, options) =>
+ {
+ calls++;
+ windows.Enqueue(window);
+ return new Engine(options.MaxStatements(1000));
+ })).WithJs().WithEventLoop();
+
+ using (var firstContext = BrowsingContext.New(config))
+ using (var secondContext = BrowsingContext.New(config))
+ {
+ var first = await firstContext.OpenAsync(request => request.Content("
first
")).ConfigureAwait(false);
+ var second = await secondContext.OpenAsync(request => request.Content("