ugly-app 0.1.143 → 0.1.144

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.
@@ -1,2 +1,2 @@
1
- export declare const CLI_VERSION = "0.1.143";
1
+ export declare const CLI_VERSION = "0.1.144";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.143";
2
+ export const CLI_VERSION = "0.1.144";
3
3
  //# sourceMappingURL=version.js.map
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Captures a screenshot of the current viewport as a base64-encoded PNG.
2
+ * Captures a screenshot of the current tab as a base64-encoded PNG.
3
+ * Uses getDisplayMedia with preferCurrentTab for pixel-perfect capture.
4
+ * Falls back to html2canvas if getDisplayMedia is unavailable.
3
5
  * Returns null if capture fails.
4
6
  */
5
7
  export declare function captureScreenshot(): Promise<string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"Screenshot.d.ts","sourceRoot":"","sources":["../../src/client/Screenshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BhE"}
1
+ {"version":3,"file":"Screenshot.d.ts","sourceRoot":"","sources":["../../src/client/Screenshot.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+DhE"}
@@ -1,8 +1,45 @@
1
1
  /**
2
- * Captures a screenshot of the current viewport as a base64-encoded PNG.
2
+ * Captures a screenshot of the current tab as a base64-encoded PNG.
3
+ * Uses getDisplayMedia with preferCurrentTab for pixel-perfect capture.
4
+ * Falls back to html2canvas if getDisplayMedia is unavailable.
3
5
  * Returns null if capture fails.
4
6
  */
5
7
  export async function captureScreenshot() {
8
+ // Try native screen capture first (Chrome 104+)
9
+ try {
10
+ const stream = await navigator.mediaDevices.getDisplayMedia({
11
+ video: { displaySurface: 'browser' },
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ preferCurrentTab: true,
14
+ });
15
+ const track = stream.getVideoTracks()[0];
16
+ if (track) {
17
+ // Use a video element to grab a single frame
18
+ const video = document.createElement('video');
19
+ video.srcObject = stream;
20
+ video.muted = true;
21
+ await video.play();
22
+ // Wait one frame for the video to render
23
+ await new Promise((r) => requestAnimationFrame(r));
24
+ const canvas = document.createElement('canvas');
25
+ canvas.width = video.videoWidth;
26
+ canvas.height = video.videoHeight;
27
+ const ctx = canvas.getContext('2d');
28
+ if (ctx) {
29
+ ctx.drawImage(video, 0, 0);
30
+ track.stop();
31
+ video.srcObject = null;
32
+ return canvas.toDataURL('image/png').split(',')[1];
33
+ }
34
+ track.stop();
35
+ video.srcObject = null;
36
+ }
37
+ stream.getTracks().forEach((t) => t.stop());
38
+ }
39
+ catch {
40
+ // getDisplayMedia not available or user denied — fall back to html2canvas
41
+ }
42
+ // Fallback: html2canvas
6
43
  try {
7
44
  const html2canvas = (await import('html2canvas')).default;
8
45
  const canvas = await html2canvas(document.body, {
@@ -18,7 +55,7 @@ export async function captureScreenshot() {
18
55
  windowHeight: window.innerHeight,
19
56
  ignoreElements: (el) => el.getAttribute('data-id') === 'feedback-button',
20
57
  });
21
- return canvas.toDataURL('image/png').split(',')[1]; // base64 only
58
+ return canvas.toDataURL('image/png').split(',')[1];
22
59
  }
23
60
  catch (err) {
24
61
  console.warn('[Screenshot] Capture failed:', err);
@@ -1 +1 @@
1
- {"version":3,"file":"Screenshot.js","sourceRoot":"","sources":["../../src/client/Screenshot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,OAGnB,CAAC;QAEhC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE;YAC9C,OAAO,EAAE,IAAI;YACb,UAAU,EAAE,IAAI;YAChB,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;YAC3C,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,MAAM,CAAC,UAAU;YACxB,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO;YACxB,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO;YACxB,WAAW,EAAE,MAAM,CAAC,UAAU;YAC9B,YAAY,EAAE,MAAM,CAAC,WAAW;YAChC,cAAc,EAAE,CAAC,EAAW,EAAE,EAAE,CAC9B,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,iBAAiB;SACnD,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc;IACpE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"Screenshot.js","sourceRoot":"","sources":["../../src/client/Screenshot.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ugly-app",
3
- "version": "0.1.143",
3
+ "version": "0.1.144",
4
4
  "type": "module",
5
5
  "main": "./dist/server/index.js",
6
6
  "exports": {
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by prebuild — do not edit manually
2
- export const CLI_VERSION = "0.1.143";
2
+ export const CLI_VERSION = "0.1.144";
@@ -1,8 +1,47 @@
1
1
  /**
2
- * Captures a screenshot of the current viewport as a base64-encoded PNG.
2
+ * Captures a screenshot of the current tab as a base64-encoded PNG.
3
+ * Uses getDisplayMedia with preferCurrentTab for pixel-perfect capture.
4
+ * Falls back to html2canvas if getDisplayMedia is unavailable.
3
5
  * Returns null if capture fails.
4
6
  */
5
7
  export async function captureScreenshot(): Promise<string | null> {
8
+ // Try native screen capture first (Chrome 104+)
9
+ try {
10
+ const stream = await navigator.mediaDevices.getDisplayMedia({
11
+ video: { displaySurface: 'browser' },
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ preferCurrentTab: true,
14
+ } as DisplayMediaStreamOptions & { preferCurrentTab: boolean });
15
+ const track = stream.getVideoTracks()[0];
16
+ if (track) {
17
+ // Use a video element to grab a single frame
18
+ const video = document.createElement('video');
19
+ video.srcObject = stream;
20
+ video.muted = true;
21
+ await video.play();
22
+
23
+ // Wait one frame for the video to render
24
+ await new Promise((r) => requestAnimationFrame(r));
25
+
26
+ const canvas = document.createElement('canvas');
27
+ canvas.width = video.videoWidth;
28
+ canvas.height = video.videoHeight;
29
+ const ctx = canvas.getContext('2d');
30
+ if (ctx) {
31
+ ctx.drawImage(video, 0, 0);
32
+ track.stop();
33
+ video.srcObject = null;
34
+ return canvas.toDataURL('image/png').split(',')[1];
35
+ }
36
+ track.stop();
37
+ video.srcObject = null;
38
+ }
39
+ stream.getTracks().forEach((t) => t.stop());
40
+ } catch {
41
+ // getDisplayMedia not available or user denied — fall back to html2canvas
42
+ }
43
+
44
+ // Fallback: html2canvas
6
45
  try {
7
46
  const html2canvas = (await import('html2canvas')).default as unknown as (
8
47
  element: HTMLElement,
@@ -23,7 +62,7 @@ export async function captureScreenshot(): Promise<string | null> {
23
62
  ignoreElements: (el: Element) =>
24
63
  el.getAttribute('data-id') === 'feedback-button',
25
64
  });
26
- return canvas.toDataURL('image/png').split(',')[1]; // base64 only
65
+ return canvas.toDataURL('image/png').split(',')[1];
27
66
  } catch (err) {
28
67
  console.warn('[Screenshot] Capture failed:', err);
29
68
  return null;