@celestia-island/hikari 0.41.1 → 0.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celestia-island/hikari",
3
- "version": "0.41.1",
3
+ "version": "0.41.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Hikari Vue 3 component library — production-grade UI components based on shittim-chest design system",
@@ -125,6 +125,48 @@ describe("createErrorReporting", () => {
125
125
  expect(overlayHost()).toBeNull();
126
126
  });
127
127
 
128
+ it("stays up for cross-origin-masked window errors", async () => {
129
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
130
+ const error = vi.spyOn(console, "error").mockImplementation(() => {});
131
+ // Earlier tests in this file spy the same methods without restoring;
132
+ // clear the accumulated calls so the assertions see only this test's.
133
+ warn.mockClear();
134
+ error.mockClear();
135
+ installPlugin();
136
+
137
+ // The masking signature: details withheld (error == null) because the
138
+ // thrower is foreign-origin code (extension / userscript), message
139
+ // pinned to "Script error." by every Chromium/Gecko/WebKit build.
140
+ window.dispatchEvent(new ErrorEvent("error", { message: "Script error.", error: null }));
141
+ await nextTick();
142
+ expect(overlayHost()).toBeNull();
143
+ expect(warn).toHaveBeenCalled();
144
+ expect(error).not.toHaveBeenCalled();
145
+
146
+ // The bare-spelling variant is masked the same way.
147
+ window.dispatchEvent(new ErrorEvent("error", { message: "Script error", error: null }));
148
+ await nextTick();
149
+ expect(overlayHost()).toBeNull();
150
+
151
+ clearGlobalError();
152
+ warn.mockRestore();
153
+ error.mockRestore();
154
+ });
155
+
156
+ it("still reports detail-less window errors that are not masked", async () => {
157
+ vi.spyOn(console, "error").mockImplementation(() => {});
158
+ installPlugin();
159
+
160
+ // error == null with a real message is a script error the browser DID
161
+ // describe — that stays reportable.
162
+ window.dispatchEvent(
163
+ new ErrorEvent("error", { message: "Uncaught SyntaxError: unexpected token", error: null }),
164
+ );
165
+ await nextTick();
166
+ expect(overlayHost()!.querySelector(".hk-error-landing__desc")!.textContent)
167
+ .toBe("Uncaught SyntaxError: unexpected token");
168
+ });
169
+
128
170
  it("chains a pre-existing app errorHandler", () => {
129
171
  vi.spyOn(console, "error").mockImplementation(() => {});
130
172
  const previous = vi.fn();
@@ -87,6 +87,21 @@ function installWindowHooks(options: HkErrorReportingOptions): void {
87
87
  const onError = (event: ErrorEvent) => {
88
88
  // Resource-load failures never reach here (no capture phase); script
89
89
  // errors always carry `error` or at least a `message`.
90
+ //
91
+ // Cross-origin-masked script errors arrive as `message: "Script
92
+ // error."` with a null `error` object: the browser withholds the
93
+ // details precisely because the thrower is NOT this origin's code
94
+ // (browser extensions / userscripts are the usual sources). A
95
+ // synthetic record for one would carry zero actionable detail and a
96
+ // stack pointing at this very handler, while the takeover rips the
97
+ // host app away from the user for noise it did not produce — log
98
+ // and stay up instead (chest demo report 2026-09-10: tapping the
99
+ // wallpaper preview in a userscript-capable mobile browser nuked
100
+ // the session with such a masked event).
101
+ if (event.error == null && /^script error\.?$/i.test(event.message)) {
102
+ console.warn("[hikari:error-reporting] ignored a cross-origin-masked script error");
103
+ return;
104
+ }
90
105
  const err = event.error ?? new Error(event.message || "Unknown script error");
91
106
  if (reportError(err, "window")) ensureOverlayMounted();
92
107
  };