fix(widget): make the bundle importable without a DOM

The package documented itself as safe to import in Node, with registration a
no-op absent a DOM. That was false: a class declaration evaluates its extends
clause at module load, so `extends globalThis.HTMLElement` threw before
canRegisterElements() could run. Caught by loading the deployed bundle rather
than the source.

Falls back to a plain base class when there is no DOM, so a server-rendering
host can import the helpers and the documented promise is now true.
This commit is contained in:
thePR0M3TH3AN committed 2026-08-10 08:36:24 -04:00
1 parent 3b95a63058
commit f697668f8f
3 files changed
+27 -2

No files matched your search

+13 -1
View File
@@ -163,7 +163,19 @@ export function targetFromAttributes(element) {
*
* Subclasses implement `render()` and may implement `template()`.
*/
export class GovernanceElement extends globalThis.HTMLElement {
/**
* Base constructor for the elements.
*
* A class declaration evaluates its `extends` clause at module load, so
* `extends globalThis.HTMLElement` throws in Node before any capability guard
* could run — which made the "safe to import without a DOM" promise false.
* Falling back to a plain class keeps the module importable for a
* server-rendering host; registration is still a no-op there.
*/
const ElementBase =
typeof globalThis.HTMLElement === "function" ? globalThis.HTMLElement : /** @type {any} */ (class {});
export class GovernanceElement extends ElementBase {
constructor() {
super();
this.attachShadow({ mode: "open" });
+4 -1
View File
@@ -34,7 +34,10 @@ export function requestContext(element) {
return detail.context;
}
export class BitGateProvider extends globalThis.HTMLElement {
const ProviderBase =
typeof globalThis.HTMLElement === "function" ? globalThis.HTMLElement : /** @type {any} */ (class {});
export class BitGateProvider extends ProviderBase {
static get observedAttributes() {
return [
"relays",
+10
View File
@@ -302,3 +302,13 @@ describe("signature verification posture", () => {
expect(provider.hasAttribute("data-unverified")).toBe(true);
});
});
describe("environment safety", () => {
it("keeps the documented promise that it imports without a DOM", async () => {
// A class declaration evaluates `extends` at module load, so this used to
// throw in Node before any capability guard could run.
const { canRegisterElements } = await import("../src/base.js");
expect(typeof canRegisterElements).toBe("function");
expect(canRegisterElements()).toBe(true); // happy-dom is present here
});
});