@koderlabs/tasks-sdk-web-reporter 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,179 @@
1
+ PROPRIETARY SOFTWARE LICENSE — ALL RIGHTS RESERVED
2
+
3
+ Copyright (c) 2026 KoderLabs. All rights reserved.
4
+ Author: Jawaid Gadiwala <jawaidgadiwala@gmail.com>
5
+
6
+ ================================================================================
7
+ 1. NO LICENSE GRANTED BY DEFAULT
8
+ ================================================================================
9
+
10
+ This software, including all source code, object code, documentation,
11
+ configuration files, build artifacts, test fixtures, and any associated
12
+ materials (collectively, the "Software"), is the proprietary and confidential
13
+ property of KoderLabs.
14
+
15
+ NO license, right, title, interest, or permission of any kind — express,
16
+ implied, statutory, by estoppel, by exhaustion, by patent exhaustion, or by
17
+ any other legal theory — is granted to any person or entity by:
18
+
19
+ (a) viewing the Software on any registry, repository, mirror, CDN,
20
+ cache, or other distribution channel (including but not limited to
21
+ npmjs.com, GitHub, GitLab, or any private registry);
22
+ (b) downloading, cloning, or otherwise obtaining a copy of the Software;
23
+ (c) the act of the Software being technically accessible due to a registry
24
+ requirement, mirror, or third-party distribution;
25
+ (d) any prior course of dealing, custom, or industry practice.
26
+
27
+ The ability to access the Software does NOT imply any permission to use it.
28
+ A separate, signed, written license agreement executed by an authorised
29
+ representative of KoderLabs is the ONLY mechanism by which any rights may be
30
+ granted.
31
+
32
+ ================================================================================
33
+ 2. PROHIBITED ACTIVITIES (NON-EXHAUSTIVE)
34
+ ================================================================================
35
+
36
+ Without prior signed written permission from KoderLabs, the following are
37
+ expressly PROHIBITED and constitute infringement, breach of contract, and
38
+ unauthorised use:
39
+
40
+ (a) Copying the Software in whole or in part, in any medium;
41
+ (b) Modifying, adapting, translating, porting, or creating derivative works
42
+ of the Software;
43
+ (c) Distributing, republishing, mirroring, hosting, transmitting,
44
+ sublicensing, leasing, lending, renting, selling, offering for sale,
45
+ bartering, gifting, or otherwise transferring the Software or any
46
+ portion of it;
47
+ (d) Forking the Software's repository, whether on GitHub, GitLab, Bitbucket,
48
+ Codeberg, Sourcehut, or any other version-control hosting service;
49
+ (e) Reverse engineering, decompiling, disassembling, deobfuscating,
50
+ extracting source from compiled or minified artifacts, or attempting to
51
+ derive the source code, algorithms, or trade secrets;
52
+ (f) Removing, altering, or obscuring any copyright, trademark, license,
53
+ attribution, or proprietary notice;
54
+ (g) Using the Software, in whole or in part, to train, fine-tune,
55
+ evaluate, or benchmark any machine-learning model, embedding model, or
56
+ AI system;
57
+ (h) Using the Software to provide a hosted service, SaaS offering,
58
+ managed offering, or any form of public or commercial offering;
59
+ (i) Using the Software in any production, staging, development, evaluation,
60
+ or testing capacity, whether commercial or non-commercial;
61
+ (j) Bypassing, disabling, or attempting to circumvent any technical
62
+ protection measure (license check, telemetry, signature verification,
63
+ etc.) embedded in the Software;
64
+ (k) Combining or integrating the Software with any work licensed under a
65
+ copyleft licence (including but not limited to GPL, AGPL, LGPL, MPL,
66
+ EPL) in a manner that would purport to relicense the Software;
67
+ (l) Filing, prosecuting, or threatening patent litigation against KoderLabs
68
+ or its customers based on any feature, design, or behaviour of the
69
+ Software ("defensive termination" — any such action automatically and
70
+ immediately terminates any rights granted to the litigant elsewhere).
71
+
72
+ ================================================================================
73
+ 3. NO IMPLIED RIGHT TO INTERNAL USE
74
+ ================================================================================
75
+
76
+ The Software is NOT licensed for internal evaluation, internal production,
77
+ internal testing, or any other internal use unless and until a separate
78
+ written commercial licence is executed. Possession of a copy of the Software,
79
+ by whatever means, confers no right to execute, run, deploy, or use it.
80
+
81
+ ================================================================================
82
+ 4. NO PATENT, TRADEMARK, OR OTHER IP GRANT
83
+ ================================================================================
84
+
85
+ No patent licence, trademark licence, trade-secret disclosure, design-right
86
+ licence, or any other intellectual-property licence is granted under this
87
+ notice. KoderLabs retains all such rights.
88
+
89
+ ================================================================================
90
+ 5. CONFIDENTIALITY
91
+ ================================================================================
92
+
93
+ The Software contains trade secrets and confidential information of
94
+ KoderLabs. Any party in possession of the Software shall (a) treat it as
95
+ confidential, (b) take reasonable measures to prevent unauthorised access or
96
+ disclosure, and (c) not disclose, publish, or make available the Software or
97
+ any portion thereof to any third party.
98
+
99
+ ================================================================================
100
+ 6. AUTOMATIC TERMINATION
101
+ ================================================================================
102
+
103
+ Any rights that may exist under a separate written agreement terminate
104
+ AUTOMATICALLY AND IMMEDIATELY upon any breach of this notice, without notice
105
+ and without judicial action. Upon termination, the breaching party shall
106
+ immediately destroy all copies of the Software in its possession or control
107
+ and certify destruction in writing to KoderLabs.
108
+
109
+ ================================================================================
110
+ 7. NO WARRANTY
111
+ ================================================================================
112
+
113
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
114
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
115
+ FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, ACCURACY, RELIABILITY,
116
+ TITLE, AVAILABILITY, OR THAT THE SOFTWARE WILL OPERATE UNINTERRUPTED OR
117
+ ERROR-FREE.
118
+
119
+ ================================================================================
120
+ 8. NO LIABILITY
121
+ ================================================================================
122
+
123
+ IN NO EVENT SHALL KODERLABS OR ITS AFFILIATES, OFFICERS, EMPLOYEES, AGENTS,
124
+ LICENSORS, OR CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
125
+ LIABILITY (INCLUDING DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
126
+ CONSEQUENTIAL, PUNITIVE, LOST PROFITS, LOST DATA, OR BUSINESS INTERRUPTION),
127
+ WHETHER IN AN ACTION OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
128
+ LIABILITY, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
129
+ SOFTWARE OR THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF
130
+ THE POSSIBILITY OF SUCH DAMAGE. IN NO EVENT SHALL KODERLABS' TOTAL CUMULATIVE
131
+ LIABILITY EXCEED ONE U.S. DOLLAR (USD 1.00).
132
+
133
+ ================================================================================
134
+ 9. EQUITABLE RELIEF
135
+ ================================================================================
136
+
137
+ The parties acknowledge that any breach of this notice would cause
138
+ irreparable harm to KoderLabs for which monetary damages would be inadequate.
139
+ KoderLabs is therefore entitled, in addition to all other remedies available
140
+ at law, to specific performance and injunctive relief without the need to
141
+ post bond.
142
+
143
+ ================================================================================
144
+ 10. GOVERNING LAW AND VENUE
145
+ ================================================================================
146
+
147
+ This notice shall be governed by and construed in accordance with the laws
148
+ of the Islamic Republic of Pakistan, without regard to its conflict-of-laws
149
+ principles. Any dispute arising out of or in connection with this notice
150
+ shall be subject to the exclusive jurisdiction of the courts of Karachi,
151
+ Pakistan.
152
+
153
+ The United Nations Convention on Contracts for the International Sale of
154
+ Goods shall not apply.
155
+
156
+ ================================================================================
157
+ 11. SEVERABILITY AND ENTIRE NOTICE
158
+ ================================================================================
159
+
160
+ If any provision of this notice is held invalid or unenforceable, the
161
+ remaining provisions shall continue in full force and effect. This notice,
162
+ together with any separate signed written licence executed between KoderLabs
163
+ and a licensee, constitutes the entire agreement concerning the Software and
164
+ supersedes all prior or contemporaneous understandings.
165
+
166
+ ================================================================================
167
+ 12. CONTACT
168
+ ================================================================================
169
+
170
+ For licensing inquiries, audit requests, or notice of suspected
171
+ infringement, contact:
172
+
173
+ KoderLabs
174
+ Attn: Jawaid Gadiwala
175
+ Email: jawaidgadiwala@gmail.com
176
+
177
+ ================================================================================
178
+ END OF LICENCE
179
+ ================================================================================
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # Proprietary Software
2
+
3
+ KoderLabs proprietary. All rights reserved.
4
+
5
+ See the bundled `LICENSE` for terms. No grant of any rights, express or
6
+ implied, is conferred by access to or possession of this package. A
7
+ separate signed written licence from KoderLabs is required for any use.
8
+
9
+ Licensing inquiries: jawaidgadiwala@gmail.com
@@ -0,0 +1,309 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/metadata.ts
5
+ var RING_SIZE = 50;
6
+ var consoleRing = [];
7
+ var consolePatched = false;
8
+ function patchConsole() {
9
+ if (consolePatched) return () => {
10
+ };
11
+ consolePatched = true;
12
+ consoleRing = [];
13
+ const levels = [
14
+ "log",
15
+ "warn",
16
+ "error",
17
+ "info",
18
+ "debug"
19
+ ];
20
+ const originals = {};
21
+ for (const level of levels) {
22
+ originals[level] = console[level];
23
+ const orig = originals[level];
24
+ console[level] = (...args) => {
25
+ orig.call(console, ...args);
26
+ consoleRing.push({
27
+ level,
28
+ args: args.map((a) => typeof a === "string" ? a : (() => {
29
+ try {
30
+ return JSON.stringify(a);
31
+ } catch {
32
+ return String(a);
33
+ }
34
+ })()),
35
+ ts: Date.now()
36
+ });
37
+ if (consoleRing.length > RING_SIZE) consoleRing.shift();
38
+ };
39
+ }
40
+ return () => {
41
+ for (const level of levels) {
42
+ if (originals[level]) console[level] = originals[level];
43
+ }
44
+ consolePatched = false;
45
+ };
46
+ }
47
+ __name(patchConsole, "patchConsole");
48
+ function getConsoleTail() {
49
+ return [
50
+ ...consoleRing
51
+ ];
52
+ }
53
+ __name(getConsoleTail, "getConsoleTail");
54
+ function getAppVersion() {
55
+ const meta = document.querySelector('meta[name="app-version"]');
56
+ return meta?.content || void 0;
57
+ }
58
+ __name(getAppVersion, "getAppVersion");
59
+ async function collectMetadata(captureConsole = false, customDataFn) {
60
+ const meta = {
61
+ url: window.location.href,
62
+ userAgent: navigator.userAgent,
63
+ viewport: {
64
+ width: window.innerWidth,
65
+ height: window.innerHeight
66
+ },
67
+ appVersion: getAppVersion()
68
+ };
69
+ safe(() => {
70
+ meta.screen = {
71
+ width: window.screen?.width ?? 0,
72
+ height: window.screen?.height ?? 0,
73
+ dpr: window.devicePixelRatio || 1
74
+ };
75
+ });
76
+ safe(async () => {
77
+ meta.browser = await detectBrowser();
78
+ });
79
+ safe(() => {
80
+ meta.os = detectOs(navigator.userAgent);
81
+ });
82
+ safe(() => {
83
+ const nav = navigator;
84
+ const perf = performance.memory;
85
+ meta.device = {
86
+ deviceMemoryGB: nav.deviceMemory,
87
+ hardwareConcurrency: nav.hardwareConcurrency,
88
+ jsHeapUsedMB: perf ? +(perf.usedJSHeapSize / 1048576).toFixed(1) : void 0,
89
+ jsHeapTotalMB: perf ? +(perf.totalJSHeapSize / 1048576).toFixed(1) : void 0
90
+ };
91
+ });
92
+ safe(() => {
93
+ const c = navigator.connection;
94
+ meta.network = {
95
+ online: navigator.onLine,
96
+ effectiveType: c?.effectiveType,
97
+ downlinkMbps: c?.downlink,
98
+ rttMs: c?.rtt,
99
+ saveData: c?.saveData
100
+ };
101
+ });
102
+ safe(() => {
103
+ meta.languages = Array.from(navigator.languages ?? [
104
+ navigator.language
105
+ ]);
106
+ const fmt = Intl.DateTimeFormat().resolvedOptions();
107
+ meta.timezone = fmt.timeZone;
108
+ meta.timezoneOffsetMin = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
109
+ });
110
+ safe(() => {
111
+ meta.preferences = {
112
+ colorScheme: matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light",
113
+ reducedMotion: matchMedia("(prefers-reduced-motion: reduce)").matches,
114
+ contrast: matchMedia("(prefers-contrast: more)").matches ? "more" : matchMedia("(prefers-contrast: less)").matches ? "less" : "no-preference"
115
+ };
116
+ });
117
+ safe(() => {
118
+ meta.referrer = document.referrer || void 0;
119
+ });
120
+ safe(() => {
121
+ const nav = performance.getEntriesByType("navigation")[0];
122
+ if (nav) {
123
+ meta.pageLoad = {
124
+ domContentLoadedMs: Math.round(nav.domContentLoadedEventEnd),
125
+ loadCompleteMs: Math.round(nav.loadEventEnd),
126
+ ttfbMs: Math.round(nav.responseStart)
127
+ };
128
+ }
129
+ });
130
+ safe(() => {
131
+ meta.clientTime = (/* @__PURE__ */ new Date()).toISOString();
132
+ });
133
+ if (captureConsole) {
134
+ meta.consoleTail = getConsoleTail();
135
+ }
136
+ if (customDataFn) {
137
+ try {
138
+ meta.customData = await customDataFn();
139
+ } catch {
140
+ }
141
+ }
142
+ return meta;
143
+ }
144
+ __name(collectMetadata, "collectMetadata");
145
+ function safe(fn) {
146
+ try {
147
+ const r = fn();
148
+ if (r && typeof r.catch === "function") {
149
+ r.catch(() => {
150
+ });
151
+ }
152
+ } catch {
153
+ }
154
+ }
155
+ __name(safe, "safe");
156
+ async function detectBrowser() {
157
+ const uad = navigator.userAgentData;
158
+ if (uad) {
159
+ try {
160
+ const high = await uad.getHighEntropyValues([
161
+ "fullVersionList"
162
+ ]);
163
+ const brands = high.fullVersionList ?? uad.brands;
164
+ const real = brands.find((b) => !/not.?a.?brand|chromium/i.test(b.brand)) ?? brands[0];
165
+ if (real) {
166
+ const major = real.version.split(".")[0];
167
+ return {
168
+ name: real.brand,
169
+ version: real.version,
170
+ major,
171
+ mobile: uad.mobile
172
+ };
173
+ }
174
+ } catch {
175
+ }
176
+ }
177
+ const ua = navigator.userAgent;
178
+ const match = ua.match(/Firefox\/(\d+(?:\.\d+)*)/) || ua.match(/Edg\/(\d+(?:\.\d+)*)/) || ua.match(/Chrome\/(\d+(?:\.\d+)*)/) || ua.match(/Version\/(\d+(?:\.\d+)*).*Safari/);
179
+ if (match) {
180
+ const name = ua.includes("Firefox") ? "Firefox" : ua.includes("Edg/") ? "Edge" : ua.includes("Chrome") ? "Chrome" : "Safari";
181
+ return {
182
+ name,
183
+ version: match[1],
184
+ major: match[1].split(".")[0],
185
+ mobile: /Mobi|Android/i.test(ua)
186
+ };
187
+ }
188
+ return {
189
+ mobile: /Mobi|Android/i.test(ua)
190
+ };
191
+ }
192
+ __name(detectBrowser, "detectBrowser");
193
+ function detectOs(ua) {
194
+ if (/Windows NT 10/.test(ua)) return {
195
+ name: "Windows",
196
+ version: "10/11"
197
+ };
198
+ if (/Windows NT (\d+\.\d+)/.test(ua)) return {
199
+ name: "Windows",
200
+ version: RegExp.$1
201
+ };
202
+ if (/Mac OS X (\d+[._]\d+(?:[._]\d+)?)/.test(ua)) return {
203
+ name: "macOS",
204
+ version: RegExp.$1.replace(/_/g, ".")
205
+ };
206
+ if (/Android (\d+(?:\.\d+)?)/.test(ua)) return {
207
+ name: "Android",
208
+ version: RegExp.$1
209
+ };
210
+ if (/iPhone OS (\d+_\d+(?:_\d+)?)/.test(ua)) return {
211
+ name: "iOS",
212
+ version: RegExp.$1.replace(/_/g, ".")
213
+ };
214
+ if (/iPad/.test(ua)) return {
215
+ name: "iPadOS"
216
+ };
217
+ if (/Linux/.test(ua)) return {
218
+ name: "Linux"
219
+ };
220
+ return {};
221
+ }
222
+ __name(detectOs, "detectOs");
223
+ function formatMetadataBlock(meta) {
224
+ const rows = [];
225
+ const push = /* @__PURE__ */ __name((label, value) => {
226
+ if (value !== void 0 && value !== null && value !== "") rows.push([
227
+ label,
228
+ value
229
+ ]);
230
+ }, "push");
231
+ push("URL", meta.url);
232
+ push("Referrer", meta.referrer);
233
+ push("App Version", meta.appVersion);
234
+ push("Client Time", meta.clientTime);
235
+ if (meta.browser?.name) {
236
+ const v = `${meta.browser.name} ${meta.browser.major ?? meta.browser.version ?? ""}`.trim() + (meta.browser.mobile ? " (mobile)" : "");
237
+ push("Browser", v);
238
+ }
239
+ if (meta.os?.name) {
240
+ push("OS", `${meta.os.name}${meta.os.version ? " " + meta.os.version : ""}`);
241
+ }
242
+ push("Viewport", `${meta.viewport.width}\xD7${meta.viewport.height}`);
243
+ if (meta.screen) {
244
+ push("Screen", `${meta.screen.width}\xD7${meta.screen.height} @${meta.screen.dpr}x DPR`);
245
+ }
246
+ if (meta.languages?.length) push("Locale", meta.languages.slice(0, 3).join(", "));
247
+ if (meta.timezone) {
248
+ const offset = meta.timezoneOffsetMin != null ? ` (UTC${meta.timezoneOffsetMin >= 0 ? "+" : ""}${meta.timezoneOffsetMin / 60})` : "";
249
+ push("Timezone", `${meta.timezone}${offset}`);
250
+ }
251
+ if (meta.device) {
252
+ const parts = [];
253
+ if (meta.device.deviceMemoryGB) parts.push(`${meta.device.deviceMemoryGB} GB RAM`);
254
+ if (meta.device.hardwareConcurrency) parts.push(`${meta.device.hardwareConcurrency} CPU`);
255
+ if (meta.device.jsHeapUsedMB != null) parts.push(`JS heap ${meta.device.jsHeapUsedMB}/${meta.device.jsHeapTotalMB} MB`);
256
+ if (parts.length) push("Device", parts.join(" \xB7 "));
257
+ }
258
+ if (meta.network) {
259
+ const parts = [
260
+ `online: ${meta.network.online ? "yes" : "no"}`
261
+ ];
262
+ if (meta.network.effectiveType) parts.push(meta.network.effectiveType);
263
+ if (meta.network.downlinkMbps != null) parts.push(`${meta.network.downlinkMbps} Mbps`);
264
+ if (meta.network.rttMs != null) parts.push(`${meta.network.rttMs} ms RTT`);
265
+ if (meta.network.saveData) parts.push("Data Saver");
266
+ push("Network", parts.join(" \xB7 "));
267
+ }
268
+ if (meta.preferences) {
269
+ const parts = [];
270
+ if (meta.preferences.colorScheme) parts.push(`color: ${meta.preferences.colorScheme}`);
271
+ if (meta.preferences.reducedMotion) parts.push("reduced motion");
272
+ if (meta.preferences.contrast && meta.preferences.contrast !== "no-preference") {
273
+ parts.push(`contrast: ${meta.preferences.contrast}`);
274
+ }
275
+ if (parts.length) push("Preferences", parts.join(" \xB7 "));
276
+ }
277
+ if (meta.pageLoad) {
278
+ const parts = [];
279
+ if (meta.pageLoad.ttfbMs != null) parts.push(`TTFB ${meta.pageLoad.ttfbMs} ms`);
280
+ if (meta.pageLoad.domContentLoadedMs != null) parts.push(`DCL ${meta.pageLoad.domContentLoadedMs} ms`);
281
+ if (meta.pageLoad.loadCompleteMs != null) parts.push(`load ${meta.pageLoad.loadCompleteMs} ms`);
282
+ if (parts.length) push("Page Load", parts.join(" \xB7 "));
283
+ }
284
+ push("User Agent", meta.userAgent);
285
+ const escape = /* @__PURE__ */ __name((s) => s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;"), "escape");
286
+ const rowParas = rows.map(([k, v]) => `<p><strong>${escape(k)}:</strong> ${escape(String(v))}</p>`).join("");
287
+ let extras = "";
288
+ if (meta.customData && Object.keys(meta.customData).length > 0) {
289
+ const items = Object.entries(meta.customData).map(([k, v]) => `<li><strong>${escape(k)}:</strong> ${escape(typeof v === "object" ? JSON.stringify(v) : String(v))}</li>`).join("");
290
+ extras += `<p><strong>Custom Data</strong></p><ul>${items}</ul>`;
291
+ }
292
+ if (meta.consoleTail && meta.consoleTail.length > 0) {
293
+ const log = meta.consoleTail.map((e) => `[${e.level.toUpperCase()}] ${escape(e.args.join(" "))}`).join("\n");
294
+ extras += `<p><strong>Console (last 50)</strong></p><pre><code>\`\`\`
295
+ ${log}
296
+ \`\`\`</code></pre>`;
297
+ }
298
+ return `<details><summary>Environment</summary><hr>${rowParas}${extras}</details>`;
299
+ }
300
+ __name(formatMetadataBlock, "formatMetadataBlock");
301
+
302
+ export {
303
+ __name,
304
+ patchConsole,
305
+ getConsoleTail,
306
+ collectMetadata,
307
+ formatMetadataBlock
308
+ };
309
+ //# sourceMappingURL=chunk-LDKYNLXK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/metadata.ts"],"sourcesContent":["/**\n * Metadata collector.\n *\n * Collects:\n * - url: current window.location.href\n * - userAgent: navigator.userAgent\n * - viewport: { width, height }\n * - appVersion: from <meta name=\"app-version\" content=\"…\"> if present\n * - consoleTail: last N console messages (ring buffer, opt-in via captureConsole)\n * - customData: lazy callback result (Jam-style pattern)\n */\n\nimport type { Serializable } from '@koderlabs/tasks-sdk-types';\n\nexport interface ConsoleEntry {\n level: 'log' | 'warn' | 'error' | 'info' | 'debug';\n args: string[];\n ts: number;\n}\n\nexport interface BrowserInfo {\n name?: string;\n version?: string;\n major?: string;\n mobile?: boolean;\n}\n\nexport interface OsInfo {\n name?: string;\n version?: string;\n}\n\nexport interface DeviceInfo {\n deviceMemoryGB?: number;\n hardwareConcurrency?: number;\n jsHeapUsedMB?: number;\n jsHeapTotalMB?: number;\n}\n\nexport interface NetworkInfo {\n online?: boolean;\n effectiveType?: string; // 'slow-2g' | '2g' | '3g' | '4g'\n downlinkMbps?: number;\n rttMs?: number;\n saveData?: boolean;\n}\n\nexport interface CollectedMetadata {\n url: string;\n userAgent: string;\n viewport: { width: number; height: number };\n appVersion?: string;\n consoleTail?: ConsoleEntry[];\n customData?: Record<string, Serializable>;\n /** Physical screen resolution (independent of window size). */\n screen?: { width: number; height: number; dpr: number };\n /** Parsed from userAgentData (Chromium) or UA regex. */\n browser?: BrowserInfo;\n /** Parsed OS name + version. */\n os?: OsInfo;\n /** Hardware capabilities. */\n device?: DeviceInfo;\n /** Network conditions at submit time. */\n network?: NetworkInfo;\n /** BCP-47 language tags from `navigator.languages`. */\n languages?: string[];\n /** IANA timezone name (e.g. `America/New_York`). */\n timezone?: string;\n /** UTC offset in minutes at submit time. */\n timezoneOffsetMin?: number;\n /** User-agent preference signals. */\n preferences?: { colorScheme?: 'light' | 'dark'; reducedMotion?: boolean; contrast?: 'no-preference' | 'more' | 'less' };\n /** Document referrer at the moment of the report. */\n referrer?: string;\n /** Navigation timing snapshot — useful for \"was the page slow?\" reports. */\n pageLoad?: { domContentLoadedMs?: number; loadCompleteMs?: number; ttfbMs?: number };\n /** Wall-clock at submit time (server already has receive time; this is the user's). */\n clientTime?: string;\n}\n\nconst RING_SIZE = 50;\n\nlet consoleRing: ConsoleEntry[] = [];\nlet consolePatched = false;\n\n/** Patch global console to capture a ring buffer of log calls. */\nexport function patchConsole(): () => void {\n if (consolePatched) return () => {};\n consolePatched = true;\n consoleRing = [];\n\n const levels: Array<ConsoleEntry['level']> = ['log', 'warn', 'error', 'info', 'debug'];\n // Save the original method references unmodified so cleanup can restore\n // strict identity (`console.log === savedOriginal`). `.bind()` would return\n // a NEW function and break that equality.\n const originals: Partial<Record<ConsoleEntry['level'], typeof console.log>> = {};\n\n for (const level of levels) {\n originals[level] = console[level];\n const orig = originals[level]!;\n console[level] = (...args: unknown[]) => {\n orig.call(console, ...args);\n consoleRing.push({\n level,\n args: args.map((a) =>\n typeof a === 'string' ? a : (() => { try { return JSON.stringify(a); } catch { return String(a); } })()\n ),\n ts: Date.now(),\n });\n if (consoleRing.length > RING_SIZE) consoleRing.shift();\n };\n }\n\n return () => {\n for (const level of levels) {\n if (originals[level]) console[level] = originals[level]!;\n }\n consolePatched = false;\n };\n}\n\n/** Get a snapshot of the current console ring buffer. */\nexport function getConsoleTail(): ConsoleEntry[] {\n return [...consoleRing];\n}\n\n/** Read <meta name=\"app-version\" content=\"…\"> if present. */\nfunction getAppVersion(): string | undefined {\n const meta = document.querySelector<HTMLMetaElement>('meta[name=\"app-version\"]');\n return meta?.content || undefined;\n}\n\n/**\n * Collect current-page metadata snapshot.\n *\n * @param captureConsole - Include console ring buffer. Default: false.\n * @param customDataFn - Lazy callback that returns extra key/value data.\n */\nexport async function collectMetadata(\n captureConsole = false,\n customDataFn?: () => Record<string, Serializable> | Promise<Record<string, Serializable>>,\n): Promise<CollectedMetadata> {\n const meta: CollectedMetadata = {\n url: window.location.href,\n userAgent: navigator.userAgent,\n viewport: { width: window.innerWidth, height: window.innerHeight },\n appVersion: getAppVersion(),\n };\n\n // Wrap each enrichment in try/catch — none of these are critical, and\n // exotic browsers may not expose every API. Single failure must never\n // block submission.\n safe(() => {\n meta.screen = {\n width: window.screen?.width ?? 0,\n height: window.screen?.height ?? 0,\n dpr: window.devicePixelRatio || 1,\n };\n });\n safe(async () => { meta.browser = await detectBrowser(); });\n safe(() => { meta.os = detectOs(navigator.userAgent); });\n safe(() => {\n const nav = navigator as Navigator & { deviceMemory?: number; hardwareConcurrency?: number };\n const perf = (performance as Performance & { memory?: { usedJSHeapSize: number; totalJSHeapSize: number } }).memory;\n meta.device = {\n deviceMemoryGB: nav.deviceMemory,\n hardwareConcurrency: nav.hardwareConcurrency,\n jsHeapUsedMB: perf ? +(perf.usedJSHeapSize / 1048576).toFixed(1) : undefined,\n jsHeapTotalMB: perf ? +(perf.totalJSHeapSize / 1048576).toFixed(1) : undefined,\n };\n });\n safe(() => {\n const c = (navigator as Navigator & { connection?: { effectiveType?: string; downlink?: number; rtt?: number; saveData?: boolean } }).connection;\n meta.network = {\n online: navigator.onLine,\n effectiveType: c?.effectiveType,\n downlinkMbps: c?.downlink,\n rttMs: c?.rtt,\n saveData: c?.saveData,\n };\n });\n safe(() => {\n meta.languages = Array.from(navigator.languages ?? [navigator.language]);\n const fmt = Intl.DateTimeFormat().resolvedOptions();\n meta.timezone = fmt.timeZone;\n meta.timezoneOffsetMin = -new Date().getTimezoneOffset();\n });\n safe(() => {\n meta.preferences = {\n colorScheme: matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',\n reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,\n contrast: matchMedia('(prefers-contrast: more)').matches\n ? 'more'\n : matchMedia('(prefers-contrast: less)').matches\n ? 'less'\n : 'no-preference',\n };\n });\n safe(() => { meta.referrer = document.referrer || undefined; });\n safe(() => {\n const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined;\n if (nav) {\n meta.pageLoad = {\n domContentLoadedMs: Math.round(nav.domContentLoadedEventEnd),\n loadCompleteMs: Math.round(nav.loadEventEnd),\n ttfbMs: Math.round(nav.responseStart),\n };\n }\n });\n safe(() => { meta.clientTime = new Date().toISOString(); });\n\n if (captureConsole) {\n meta.consoleTail = getConsoleTail();\n }\n\n if (customDataFn) {\n try {\n meta.customData = await customDataFn();\n } catch {\n // Don't let customData failures block submission\n }\n }\n\n return meta;\n}\n\nfunction safe(fn: () => unknown | Promise<unknown>): void {\n try {\n const r = fn();\n if (r && typeof (r as Promise<unknown>).catch === 'function') {\n (r as Promise<unknown>).catch(() => {});\n }\n } catch {/* swallow */}\n}\n\n/** Use modern userAgentData when available; otherwise UA-regex fallback. */\nasync function detectBrowser(): Promise<BrowserInfo> {\n const uad = (navigator as Navigator & {\n userAgentData?: {\n mobile: boolean;\n brands: Array<{ brand: string; version: string }>;\n getHighEntropyValues: (hints: string[]) => Promise<{ fullVersionList?: Array<{ brand: string; version: string }> }>;\n };\n }).userAgentData;\n\n if (uad) {\n try {\n const high = await uad.getHighEntropyValues(['fullVersionList']);\n const brands = high.fullVersionList ?? uad.brands;\n // Pick the non-generic brand (Chromium / \"Not?A_Brand\" come last)\n const real =\n brands.find((b) => !/not.?a.?brand|chromium/i.test(b.brand)) ??\n brands[0];\n if (real) {\n const major = real.version.split('.')[0];\n return { name: real.brand, version: real.version, major, mobile: uad.mobile };\n }\n } catch {/* fall through to UA regex */}\n }\n\n // UA regex fallback — covers Firefox, Safari, and ancient Chromium\n const ua = navigator.userAgent;\n const match =\n ua.match(/Firefox\\/(\\d+(?:\\.\\d+)*)/) ||\n ua.match(/Edg\\/(\\d+(?:\\.\\d+)*)/) ||\n ua.match(/Chrome\\/(\\d+(?:\\.\\d+)*)/) ||\n ua.match(/Version\\/(\\d+(?:\\.\\d+)*).*Safari/);\n if (match) {\n const name = ua.includes('Firefox') ? 'Firefox'\n : ua.includes('Edg/') ? 'Edge'\n : ua.includes('Chrome') ? 'Chrome'\n : 'Safari';\n return { name, version: match[1], major: match[1].split('.')[0], mobile: /Mobi|Android/i.test(ua) };\n }\n return { mobile: /Mobi|Android/i.test(ua) };\n}\n\nfunction detectOs(ua: string): OsInfo {\n if (/Windows NT 10/.test(ua)) return { name: 'Windows', version: '10/11' };\n if (/Windows NT (\\d+\\.\\d+)/.test(ua)) return { name: 'Windows', version: RegExp.$1 };\n if (/Mac OS X (\\d+[._]\\d+(?:[._]\\d+)?)/.test(ua)) return { name: 'macOS', version: RegExp.$1.replace(/_/g, '.') };\n if (/Android (\\d+(?:\\.\\d+)?)/.test(ua)) return { name: 'Android', version: RegExp.$1 };\n if (/iPhone OS (\\d+_\\d+(?:_\\d+)?)/.test(ua)) return { name: 'iOS', version: RegExp.$1.replace(/_/g, '.') };\n if (/iPad/.test(ua)) return { name: 'iPadOS' };\n if (/Linux/.test(ua)) return { name: 'Linux' };\n return {};\n}\n\n/**\n * Format collected metadata as a collapsible markdown block.\n * Appended to the ticket description body.\n */\n/**\n * Format collected metadata as an HTML block.\n *\n * Output is HTML — not markdown — because ticket descriptions in\n * InstantTasks are stored as TipTap-compatible HTML and the renderer\n * does NOT post-process markdown. Returning `**bold**` and bare `\\n`\n * would render as literal asterisks on one collapsed line.\n */\nexport function formatMetadataBlock(meta: CollectedMetadata): string {\n const rows: Array<[string, string | undefined | null]> = [];\n\n const push = (label: string, value: string | undefined | null) => {\n if (value !== undefined && value !== null && value !== '') rows.push([label, value]);\n };\n\n push('URL', meta.url);\n push('Referrer', meta.referrer);\n push('App Version', meta.appVersion);\n push('Client Time', meta.clientTime);\n\n if (meta.browser?.name) {\n const v = `${meta.browser.name} ${meta.browser.major ?? meta.browser.version ?? ''}`.trim()\n + (meta.browser.mobile ? ' (mobile)' : '');\n push('Browser', v);\n }\n if (meta.os?.name) {\n push('OS', `${meta.os.name}${meta.os.version ? ' ' + meta.os.version : ''}`);\n }\n\n push('Viewport', `${meta.viewport.width}×${meta.viewport.height}`);\n if (meta.screen) {\n push('Screen', `${meta.screen.width}×${meta.screen.height} @${meta.screen.dpr}x DPR`);\n }\n\n if (meta.languages?.length) push('Locale', meta.languages.slice(0, 3).join(', '));\n if (meta.timezone) {\n const offset = meta.timezoneOffsetMin != null\n ? ` (UTC${meta.timezoneOffsetMin >= 0 ? '+' : ''}${meta.timezoneOffsetMin / 60})`\n : '';\n push('Timezone', `${meta.timezone}${offset}`);\n }\n\n if (meta.device) {\n const parts: string[] = [];\n if (meta.device.deviceMemoryGB) parts.push(`${meta.device.deviceMemoryGB} GB RAM`);\n if (meta.device.hardwareConcurrency) parts.push(`${meta.device.hardwareConcurrency} CPU`);\n if (meta.device.jsHeapUsedMB != null) parts.push(`JS heap ${meta.device.jsHeapUsedMB}/${meta.device.jsHeapTotalMB} MB`);\n if (parts.length) push('Device', parts.join(' · '));\n }\n\n if (meta.network) {\n const parts: string[] = [`online: ${meta.network.online ? 'yes' : 'no'}`];\n if (meta.network.effectiveType) parts.push(meta.network.effectiveType);\n if (meta.network.downlinkMbps != null) parts.push(`${meta.network.downlinkMbps} Mbps`);\n if (meta.network.rttMs != null) parts.push(`${meta.network.rttMs} ms RTT`);\n if (meta.network.saveData) parts.push('Data Saver');\n push('Network', parts.join(' · '));\n }\n\n if (meta.preferences) {\n const parts: string[] = [];\n if (meta.preferences.colorScheme) parts.push(`color: ${meta.preferences.colorScheme}`);\n if (meta.preferences.reducedMotion) parts.push('reduced motion');\n if (meta.preferences.contrast && meta.preferences.contrast !== 'no-preference') {\n parts.push(`contrast: ${meta.preferences.contrast}`);\n }\n if (parts.length) push('Preferences', parts.join(' · '));\n }\n\n if (meta.pageLoad) {\n const parts: string[] = [];\n if (meta.pageLoad.ttfbMs != null) parts.push(`TTFB ${meta.pageLoad.ttfbMs} ms`);\n if (meta.pageLoad.domContentLoadedMs != null) parts.push(`DCL ${meta.pageLoad.domContentLoadedMs} ms`);\n if (meta.pageLoad.loadCompleteMs != null) parts.push(`load ${meta.pageLoad.loadCompleteMs} ms`);\n if (parts.length) push('Page Load', parts.join(' · '));\n }\n\n push('User Agent', meta.userAgent);\n\n const escape = (s: string) =>\n s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\n // Render one `<p>` per key/value so the TipTap renderer (which sanitizes\n // away `<table>` / `<details>` / `<summary>`) still keeps the line breaks.\n // The `:` separator is enough for visual scanning without needing a grid.\n const rowParas = rows\n .map(([k, v]) => `<p><strong>${escape(k)}:</strong> ${escape(String(v))}</p>`)\n .join('');\n\n let extras = '';\n\n if (meta.customData && Object.keys(meta.customData).length > 0) {\n const items = Object.entries(meta.customData)\n .map(([k, v]) => `<li><strong>${escape(k)}:</strong> ${escape(typeof v === 'object' ? JSON.stringify(v) : String(v))}</li>`)\n .join('');\n extras += `<p><strong>Custom Data</strong></p><ul>${items}</ul>`;\n }\n\n if (meta.consoleTail && meta.consoleTail.length > 0) {\n const log = meta.consoleTail\n .map((e) => `[${e.level.toUpperCase()}] ${escape(e.args.join(' '))}`)\n .join('\\n');\n // Fenced code block (```) inside <pre><code> — the fence markers keep the\n // log readable when the HTML is round-tripped through markdown renderers\n // (GitHub mirror, Slack preview, etc.).\n extras += `<p><strong>Console (last 50)</strong></p><pre><code>\\`\\`\\`\\n${log}\\n\\`\\`\\`</code></pre>`;\n }\n\n // Wrap in <details>/<summary> so the environment block is collapsed by\n // default in renderers that support it. TipTap-style sanitizers that drop\n // these tags will still see the inner <p> rows.\n return `<details><summary>Environment</summary><hr>${rowParas}${extras}</details>`;\n}\n"],"mappings":"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","names":["RING_SIZE","consoleRing","consolePatched","patchConsole","levels","originals","level","console","orig","args","call","push","map","a","JSON","stringify","String","ts","Date","now","length","shift","getConsoleTail","getAppVersion","meta","document","querySelector","content","undefined","collectMetadata","captureConsole","customDataFn","url","window","location","href","userAgent","navigator","viewport","width","innerWidth","height","innerHeight","appVersion","safe","screen","dpr","devicePixelRatio","browser","detectBrowser","os","detectOs","nav","perf","performance","memory","device","deviceMemoryGB","deviceMemory","hardwareConcurrency","jsHeapUsedMB","usedJSHeapSize","toFixed","jsHeapTotalMB","totalJSHeapSize","c","connection","network","online","onLine","effectiveType","downlinkMbps","downlink","rttMs","rtt","saveData","languages","Array","from","language","fmt","Intl","DateTimeFormat","resolvedOptions","timezone","timeZone","timezoneOffsetMin","getTimezoneOffset","preferences","colorScheme","matchMedia","matches","reducedMotion","contrast","referrer","getEntriesByType","pageLoad","domContentLoadedMs","Math","round","domContentLoadedEventEnd","loadCompleteMs","loadEventEnd","ttfbMs","responseStart","clientTime","toISOString","consoleTail","customData","fn","r","catch","uad","userAgentData","high","getHighEntropyValues","brands","fullVersionList","real","find","b","test","brand","major","version","split","name","mobile","ua","match","includes","RegExp","$1","replace","formatMetadataBlock","rows","label","value","v","trim","slice","join","offset","parts","escape","s","rowParas","k","extras","Object","keys","items","entries","log","e","toUpperCase"]}