refactor(app): Move heavy initialization from constructor to setup()

- Introduces a `setup()` method in `Application` class to handle complex initialization and side effects.
- Updates `constructor` to be lightweight, only storing configuration options.
- Updates `js/bootstrap.js`, `js/embed.js`, and relevant tests to call `app.setup()` explicitly after instantiation.
- Resolves "Heavy Constructor" code health issue.
- Fixes `tests/video-modal-zap.test.mjs` environment issue with `globalThis.navigator`.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-08 03:44:38 +00:00
1 parent 1fbee4219b
commit 0665a3392e
5 files changed
+27 -2

No files matched your search

+11
View File
@@ -241,6 +241,15 @@ class Application {
constructor({ services = {}, ui = {}, helpers = {}, loadView: viewLoader } = {}) { constructor({ services = {}, ui = {}, helpers = {}, loadView: viewLoader } = {}) {
this.loadView = typeof viewLoader === "function" ? viewLoader : null; this.loadView = typeof viewLoader === "function" ? viewLoader : null;
this._setupOptions = { services, ui, helpers };
this._isSetup = false;
}
setup() {
if (this._isSetup) return;
this._isSetup = true;
const { services = {}, ui = {}, helpers = {} } = this._setupOptions || {};
const bootstrapServices = { const bootstrapServices = {
...services, ...services,
@@ -502,6 +511,8 @@ class Application {
}; };
onActiveSignerChanged(this.handleShareNostrSignerChange); onActiveSignerChanged(this.handleShareNostrSignerChange);
this.updateShareNostrAuthState({ reason: "init" }); this.updateShareNostrAuthState({ reason: "init" });
delete this._setupOptions;
} }
/** /**
+3 -1
View File
@@ -30,10 +30,12 @@ function mergeServices(overrides = {}) {
} }
export async function createApplication({ services, loadView: loadViewOverride } = {}) { export async function createApplication({ services, loadView: loadViewOverride } = {}) {
return new Application({ const app = new Application({
services: mergeServices(services), services: mergeServices(services),
loadView: typeof loadViewOverride === "function" ? loadViewOverride : loadView, loadView: typeof loadViewOverride === "function" ? loadViewOverride : loadView,
}); });
app.setup();
return app;
} }
export default createApplication; export default createApplication;
+2
View File
@@ -102,6 +102,8 @@ app.showSuccess = (message) => {
setStatus(message, "success"); setStatus(message, "success");
}; };
app.setup();
const resolvePlaybackPreference = (value) => { const resolvePlaybackPreference = (value) => {
if (typeof value !== "string") { if (typeof value !== "string") {
return null; return null;
+1
View File
@@ -599,6 +599,7 @@ async function setupPlaybackHarness() {
helpers, helpers,
ui: { videoModal: () => modalStub }, ui: { videoModal: () => modalStub },
}); });
app.setup();
app.showError = () => {}; app.showError = () => {};
app.showSuccess = () => {}; app.showSuccess = () => {};
+10 -1
View File
@@ -143,7 +143,15 @@ if (typeof globalThis.WebSocket === "undefined") {
} }
globalThis.document = documentStub; globalThis.document = documentStub;
globalThis.navigator = windowStub.navigator; try {
Object.defineProperty(globalThis, "navigator", {
value: windowStub.navigator,
writable: true,
configurable: true,
});
} catch (e) {
// Fallback for environments where navigator is read-only
}
globalThis.location = windowStub.location; globalThis.location = windowStub.location;
if (typeof globalThis.fetch === "undefined") { if (typeof globalThis.fetch === "undefined") {
@@ -302,6 +310,7 @@ async function createApp({ splitAndZap }) {
videoModal: () => modalStub, videoModal: () => modalStub,
}, },
}); });
app.setup();
app.boundVideoModalZapOpenHandler = (event = {}) => { app.boundVideoModalZapOpenHandler = (event = {}) => {
const requiresLogin = Boolean(event?.detail?.requiresLogin); const requiresLogin = Boolean(event?.detail?.requiresLogin);