diff --git a/packages/widget/src/base.js b/packages/widget/src/base.js index 4e347fb..f9b6f45 100644 --- a/packages/widget/src/base.js +++ b/packages/widget/src/base.js @@ -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" }); diff --git a/packages/widget/src/provider.js b/packages/widget/src/provider.js index 24e8765..8e518c8 100644 --- a/packages/widget/src/provider.js +++ b/packages/widget/src/provider.js @@ -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", diff --git a/packages/widget/test/provider.test.js b/packages/widget/test/provider.test.js index 5ed2c9d..fca1dfe 100644 --- a/packages/widget/test/provider.test.js +++ b/packages/widget/test/provider.test.js @@ -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 + }); +});