@pocketping/widget 2.4.0 → 2.5.1

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/dist/index.cjs CHANGED
@@ -2991,7 +2991,7 @@ function AttachmentDisplay({ attachment }) {
2991
2991
  }
2992
2992
 
2993
2993
  // src/version.ts
2994
- var VERSION = "0.3.8";
2994
+ var VERSION = "2.6.0";
2995
2995
 
2996
2996
  // src/client.ts
2997
2997
  function detectBotSignals() {
@@ -4024,6 +4024,14 @@ var PocketPingClient = class {
4024
4024
  console.error("[PocketPing] Failed to parse SSE message:", err);
4025
4025
  }
4026
4026
  });
4027
+ this.sse.addEventListener("screenshot_request", (event) => {
4028
+ try {
4029
+ const data = JSON.parse(event.data);
4030
+ this.handleRealtimeEvent(data);
4031
+ } catch (err) {
4032
+ console.error("[PocketPing] Failed to parse SSE screenshot_request:", err);
4033
+ }
4034
+ });
4027
4035
  this.sse.addEventListener("connected", () => {
4028
4036
  });
4029
4037
  this.sse.onerror = () => {
@@ -4206,6 +4214,10 @@ var PocketPingClient = class {
4206
4214
  this.emit("configUpdate", configData);
4207
4215
  }
4208
4216
  break;
4217
+ case "screenshot_request":
4218
+ const screenshotData = event.data;
4219
+ this.handleScreenshotRequest(screenshotData);
4220
+ break;
4209
4221
  }
4210
4222
  }
4211
4223
  // ─────────────────────────────────────────────────────────────────
@@ -4252,6 +4264,7 @@ var PocketPingClient = class {
4252
4264
  try {
4253
4265
  const lastEventTimestamp = this.getLastEventTimestamp();
4254
4266
  const newMessages = await this.fetchMessages(lastEventTimestamp ?? void 0);
4267
+ await this.pollScreenshotRequests();
4255
4268
  this.pollingFailures = 0;
4256
4269
  for (const message of newMessages) {
4257
4270
  const existingIndex = this.session.messages.findIndex((m) => m.id === message.id);
@@ -4502,6 +4515,135 @@ var PocketPingClient = class {
4502
4515
  generateId() {
4503
4516
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;
4504
4517
  }
4518
+ // ─────────────────────────────────────────────────────────────────
4519
+ // Screenshot Request Polling (for polling fallback mode)
4520
+ // ─────────────────────────────────────────────────────────────────
4521
+ async pollScreenshotRequests() {
4522
+ if (!this.session) return;
4523
+ try {
4524
+ const response = await this.fetch(`/screenshot/requests?sessionId=${this.session.sessionId}`, { method: "GET" });
4525
+ for (const request of response.requests || []) {
4526
+ this.handleScreenshotRequest(request);
4527
+ }
4528
+ } catch (err) {
4529
+ }
4530
+ }
4531
+ // ─────────────────────────────────────────────────────────────────
4532
+ // Screenshot Capture
4533
+ // ─────────────────────────────────────────────────────────────────
4534
+ /**
4535
+ * Handle screenshot request from operator
4536
+ * @param data.silent - If true, screenshot won't appear in widget chat (only sent to bridges)
4537
+ */
4538
+ async handleScreenshotRequest(data) {
4539
+ console.log("[PocketPing] Screenshot requested by", data.requestedBy, "via", data.requestedFrom, data.silent ? "(silent)" : "");
4540
+ try {
4541
+ const blob = await this.captureScreenshot();
4542
+ const initResponse = await this.fetch("/screenshot/upload", {
4543
+ method: "POST",
4544
+ body: JSON.stringify({
4545
+ sessionId: this.session?.sessionId,
4546
+ requestId: data.requestId
4547
+ })
4548
+ });
4549
+ const uploadResponse = await fetch(initResponse.uploadUrl, {
4550
+ method: "PUT",
4551
+ body: blob,
4552
+ headers: {
4553
+ "Content-Type": "image/png"
4554
+ }
4555
+ });
4556
+ if (!uploadResponse.ok) {
4557
+ throw new Error(`Upload failed: ${uploadResponse.status}`);
4558
+ }
4559
+ await this.fetch("/screenshot/upload/complete", {
4560
+ method: "POST",
4561
+ body: JSON.stringify({
4562
+ sessionId: this.session?.sessionId,
4563
+ requestId: data.requestId,
4564
+ attachmentId: initResponse.attachmentId,
4565
+ size: blob.size
4566
+ })
4567
+ });
4568
+ console.log("[PocketPing] Screenshot captured and uploaded successfully");
4569
+ } catch (error) {
4570
+ console.error("[PocketPing] Screenshot capture failed:", error);
4571
+ }
4572
+ }
4573
+ /**
4574
+ * Capture screenshot of the viewport using html2canvas
4575
+ */
4576
+ async captureScreenshot() {
4577
+ const html2canvas = await this.loadHtml2Canvas();
4578
+ const widgetContainer = document.getElementById("pocketping-widget");
4579
+ const widgetToggle = document.getElementById("pocketping-toggle");
4580
+ let widgetWasVisible = false;
4581
+ let toggleWasVisible = false;
4582
+ if (widgetContainer) {
4583
+ widgetWasVisible = widgetContainer.style.display !== "none";
4584
+ widgetContainer.style.display = "none";
4585
+ }
4586
+ if (widgetToggle) {
4587
+ toggleWasVisible = widgetToggle.style.display !== "none";
4588
+ widgetToggle.style.display = "none";
4589
+ }
4590
+ try {
4591
+ const canvas = await html2canvas(document.documentElement, {
4592
+ width: window.innerWidth,
4593
+ height: window.innerHeight,
4594
+ x: window.scrollX,
4595
+ y: window.scrollY,
4596
+ windowWidth: window.innerWidth,
4597
+ windowHeight: window.innerHeight,
4598
+ logging: false,
4599
+ useCORS: true,
4600
+ allowTaint: true
4601
+ });
4602
+ return new Promise((resolve, reject) => {
4603
+ canvas.toBlob(
4604
+ (blob) => {
4605
+ if (blob) {
4606
+ resolve(blob);
4607
+ } else {
4608
+ reject(new Error("Failed to create blob from canvas"));
4609
+ }
4610
+ },
4611
+ "image/png",
4612
+ 0.9
4613
+ );
4614
+ });
4615
+ } finally {
4616
+ if (widgetContainer && widgetWasVisible) {
4617
+ widgetContainer.style.display = "";
4618
+ }
4619
+ if (widgetToggle && toggleWasVisible) {
4620
+ widgetToggle.style.display = "";
4621
+ }
4622
+ }
4623
+ }
4624
+ /**
4625
+ * Dynamically load html2canvas from CDN
4626
+ */
4627
+ async loadHtml2Canvas() {
4628
+ const win = window;
4629
+ if (typeof win.html2canvas !== "undefined") {
4630
+ return win.html2canvas;
4631
+ }
4632
+ return new Promise((resolve, reject) => {
4633
+ const script = document.createElement("script");
4634
+ script.src = "https://cdn.jsdelivr.net/npm/html2canvas-pro@1.6.6/dist/html2canvas-pro.min.js";
4635
+ script.onload = () => {
4636
+ const w = window;
4637
+ if (typeof w.html2canvas !== "undefined") {
4638
+ resolve(w.html2canvas);
4639
+ } else {
4640
+ reject(new Error("html2canvas-pro failed to load"));
4641
+ }
4642
+ };
4643
+ script.onerror = () => reject(new Error("Failed to load html2canvas-pro from CDN"));
4644
+ document.head.appendChild(script);
4645
+ });
4646
+ }
4505
4647
  };
4506
4648
 
4507
4649
  // src/index.ts
package/dist/index.d.cts CHANGED
@@ -475,6 +475,20 @@ declare class PocketPingClient {
475
475
  private storeIdentity;
476
476
  private clearIdentity;
477
477
  private generateId;
478
+ private pollScreenshotRequests;
479
+ /**
480
+ * Handle screenshot request from operator
481
+ * @param data.silent - If true, screenshot won't appear in widget chat (only sent to bridges)
482
+ */
483
+ private handleScreenshotRequest;
484
+ /**
485
+ * Capture screenshot of the viewport using html2canvas
486
+ */
487
+ private captureScreenshot;
488
+ /**
489
+ * Dynamically load html2canvas from CDN
490
+ */
491
+ private loadHtml2Canvas;
478
492
  }
479
493
 
480
494
  declare function init(config: PocketPingConfig): PocketPingClient;
package/dist/index.d.ts CHANGED
@@ -475,6 +475,20 @@ declare class PocketPingClient {
475
475
  private storeIdentity;
476
476
  private clearIdentity;
477
477
  private generateId;
478
+ private pollScreenshotRequests;
479
+ /**
480
+ * Handle screenshot request from operator
481
+ * @param data.silent - If true, screenshot won't appear in widget chat (only sent to bridges)
482
+ */
483
+ private handleScreenshotRequest;
484
+ /**
485
+ * Capture screenshot of the viewport using html2canvas
486
+ */
487
+ private captureScreenshot;
488
+ /**
489
+ * Dynamically load html2canvas from CDN
490
+ */
491
+ private loadHtml2Canvas;
478
492
  }
479
493
 
480
494
  declare function init(config: PocketPingConfig): PocketPingClient;
package/dist/index.js CHANGED
@@ -2950,7 +2950,7 @@ function AttachmentDisplay({ attachment }) {
2950
2950
  }
2951
2951
 
2952
2952
  // src/version.ts
2953
- var VERSION = "0.3.8";
2953
+ var VERSION = "2.6.0";
2954
2954
 
2955
2955
  // src/client.ts
2956
2956
  function detectBotSignals() {
@@ -3983,6 +3983,14 @@ var PocketPingClient = class {
3983
3983
  console.error("[PocketPing] Failed to parse SSE message:", err);
3984
3984
  }
3985
3985
  });
3986
+ this.sse.addEventListener("screenshot_request", (event) => {
3987
+ try {
3988
+ const data = JSON.parse(event.data);
3989
+ this.handleRealtimeEvent(data);
3990
+ } catch (err) {
3991
+ console.error("[PocketPing] Failed to parse SSE screenshot_request:", err);
3992
+ }
3993
+ });
3986
3994
  this.sse.addEventListener("connected", () => {
3987
3995
  });
3988
3996
  this.sse.onerror = () => {
@@ -4165,6 +4173,10 @@ var PocketPingClient = class {
4165
4173
  this.emit("configUpdate", configData);
4166
4174
  }
4167
4175
  break;
4176
+ case "screenshot_request":
4177
+ const screenshotData = event.data;
4178
+ this.handleScreenshotRequest(screenshotData);
4179
+ break;
4168
4180
  }
4169
4181
  }
4170
4182
  // ─────────────────────────────────────────────────────────────────
@@ -4211,6 +4223,7 @@ var PocketPingClient = class {
4211
4223
  try {
4212
4224
  const lastEventTimestamp = this.getLastEventTimestamp();
4213
4225
  const newMessages = await this.fetchMessages(lastEventTimestamp ?? void 0);
4226
+ await this.pollScreenshotRequests();
4214
4227
  this.pollingFailures = 0;
4215
4228
  for (const message of newMessages) {
4216
4229
  const existingIndex = this.session.messages.findIndex((m) => m.id === message.id);
@@ -4461,6 +4474,135 @@ var PocketPingClient = class {
4461
4474
  generateId() {
4462
4475
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 11)}`;
4463
4476
  }
4477
+ // ─────────────────────────────────────────────────────────────────
4478
+ // Screenshot Request Polling (for polling fallback mode)
4479
+ // ─────────────────────────────────────────────────────────────────
4480
+ async pollScreenshotRequests() {
4481
+ if (!this.session) return;
4482
+ try {
4483
+ const response = await this.fetch(`/screenshot/requests?sessionId=${this.session.sessionId}`, { method: "GET" });
4484
+ for (const request of response.requests || []) {
4485
+ this.handleScreenshotRequest(request);
4486
+ }
4487
+ } catch (err) {
4488
+ }
4489
+ }
4490
+ // ─────────────────────────────────────────────────────────────────
4491
+ // Screenshot Capture
4492
+ // ─────────────────────────────────────────────────────────────────
4493
+ /**
4494
+ * Handle screenshot request from operator
4495
+ * @param data.silent - If true, screenshot won't appear in widget chat (only sent to bridges)
4496
+ */
4497
+ async handleScreenshotRequest(data) {
4498
+ console.log("[PocketPing] Screenshot requested by", data.requestedBy, "via", data.requestedFrom, data.silent ? "(silent)" : "");
4499
+ try {
4500
+ const blob = await this.captureScreenshot();
4501
+ const initResponse = await this.fetch("/screenshot/upload", {
4502
+ method: "POST",
4503
+ body: JSON.stringify({
4504
+ sessionId: this.session?.sessionId,
4505
+ requestId: data.requestId
4506
+ })
4507
+ });
4508
+ const uploadResponse = await fetch(initResponse.uploadUrl, {
4509
+ method: "PUT",
4510
+ body: blob,
4511
+ headers: {
4512
+ "Content-Type": "image/png"
4513
+ }
4514
+ });
4515
+ if (!uploadResponse.ok) {
4516
+ throw new Error(`Upload failed: ${uploadResponse.status}`);
4517
+ }
4518
+ await this.fetch("/screenshot/upload/complete", {
4519
+ method: "POST",
4520
+ body: JSON.stringify({
4521
+ sessionId: this.session?.sessionId,
4522
+ requestId: data.requestId,
4523
+ attachmentId: initResponse.attachmentId,
4524
+ size: blob.size
4525
+ })
4526
+ });
4527
+ console.log("[PocketPing] Screenshot captured and uploaded successfully");
4528
+ } catch (error) {
4529
+ console.error("[PocketPing] Screenshot capture failed:", error);
4530
+ }
4531
+ }
4532
+ /**
4533
+ * Capture screenshot of the viewport using html2canvas
4534
+ */
4535
+ async captureScreenshot() {
4536
+ const html2canvas = await this.loadHtml2Canvas();
4537
+ const widgetContainer = document.getElementById("pocketping-widget");
4538
+ const widgetToggle = document.getElementById("pocketping-toggle");
4539
+ let widgetWasVisible = false;
4540
+ let toggleWasVisible = false;
4541
+ if (widgetContainer) {
4542
+ widgetWasVisible = widgetContainer.style.display !== "none";
4543
+ widgetContainer.style.display = "none";
4544
+ }
4545
+ if (widgetToggle) {
4546
+ toggleWasVisible = widgetToggle.style.display !== "none";
4547
+ widgetToggle.style.display = "none";
4548
+ }
4549
+ try {
4550
+ const canvas = await html2canvas(document.documentElement, {
4551
+ width: window.innerWidth,
4552
+ height: window.innerHeight,
4553
+ x: window.scrollX,
4554
+ y: window.scrollY,
4555
+ windowWidth: window.innerWidth,
4556
+ windowHeight: window.innerHeight,
4557
+ logging: false,
4558
+ useCORS: true,
4559
+ allowTaint: true
4560
+ });
4561
+ return new Promise((resolve, reject) => {
4562
+ canvas.toBlob(
4563
+ (blob) => {
4564
+ if (blob) {
4565
+ resolve(blob);
4566
+ } else {
4567
+ reject(new Error("Failed to create blob from canvas"));
4568
+ }
4569
+ },
4570
+ "image/png",
4571
+ 0.9
4572
+ );
4573
+ });
4574
+ } finally {
4575
+ if (widgetContainer && widgetWasVisible) {
4576
+ widgetContainer.style.display = "";
4577
+ }
4578
+ if (widgetToggle && toggleWasVisible) {
4579
+ widgetToggle.style.display = "";
4580
+ }
4581
+ }
4582
+ }
4583
+ /**
4584
+ * Dynamically load html2canvas from CDN
4585
+ */
4586
+ async loadHtml2Canvas() {
4587
+ const win = window;
4588
+ if (typeof win.html2canvas !== "undefined") {
4589
+ return win.html2canvas;
4590
+ }
4591
+ return new Promise((resolve, reject) => {
4592
+ const script = document.createElement("script");
4593
+ script.src = "https://cdn.jsdelivr.net/npm/html2canvas-pro@1.6.6/dist/html2canvas-pro.min.js";
4594
+ script.onload = () => {
4595
+ const w = window;
4596
+ if (typeof w.html2canvas !== "undefined") {
4597
+ resolve(w.html2canvas);
4598
+ } else {
4599
+ reject(new Error("html2canvas-pro failed to load"));
4600
+ }
4601
+ };
4602
+ script.onerror = () => reject(new Error("Failed to load html2canvas-pro from CDN"));
4603
+ document.head.appendChild(script);
4604
+ });
4605
+ }
4464
4606
  };
4465
4607
 
4466
4608
  // src/index.ts