customer-chat-sdk 1.0.24 → 1.0.26

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.
@@ -12,7 +12,7 @@ export interface ScreenshotOptions {
12
12
  outputFormat?: 'webp' | 'jpeg' | 'png';
13
13
  enableCORS?: boolean;
14
14
  proxyUrl?: string;
15
- engine?: 'html2canvas';
15
+ engine?: 'modern-screenshot';
16
16
  corsMode?: 'simple' | 'smart' | 'proxy' | 'blob' | 'canvas-proxy' | 'ignore' | 'test-first';
17
17
  silentMode?: boolean;
18
18
  maxRetries?: number;
@@ -25,7 +25,7 @@ export interface UploadConfig {
25
25
  objectKey: string;
26
26
  bucketName: string;
27
27
  contentType: string;
28
- expirationMinutes: number;
28
+ ttl: number;
29
29
  duration: number;
30
30
  }
31
31
  /**
@@ -47,6 +47,7 @@ export declare class ScreenshotManager {
47
47
  private currentUploadConfig;
48
48
  private worker;
49
49
  private screenshotTimer;
50
+ private screenshotContext;
50
51
  private messageHandler;
51
52
  private dynamicInterval;
52
53
  private expirationTimer;
@@ -95,9 +96,9 @@ export declare class ScreenshotManager {
95
96
  */
96
97
  private takeScreenshot;
97
98
  /**
98
- * 使用 html2canvas 截图
99
+ * 使用 modern-screenshot 截图(启用 Worker)
99
100
  */
100
- private takeScreenshotWithHtml2Canvas;
101
+ private takeScreenshotWithModernScreenshot;
101
102
  /**
102
103
  * 预处理网络图片
103
104
  */
@@ -1 +1 @@
1
- {"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ScreenshotManager.d.ts","sourceRoot":"","sources":["../../src/core/ScreenshotManager.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var html2canvas = require('html2canvas');
5
+ var modernScreenshot = require('modern-screenshot');
6
6
 
7
7
  // 直接使用base64字符串,避免打包后路径问题
8
8
  const iconImage = 'data:image/png;base64,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';
@@ -925,7 +925,29 @@ class IframeManager {
925
925
  }
926
926
  }
927
927
 
928
- // @ts-ignore - html2canvas may not have type definitions
928
+ // @ts-ignore - modern-screenshot may not have type definitions
929
+ // Worker URL 将在创建上下文时动态获取
930
+ // 在 Vite 环境中可以使用: import workerUrl from 'modern-screenshot/worker?url'
931
+ // 在 Rollup 中,modern-screenshot 会自动处理 worker URL
932
+ let workerUrl = undefined;
933
+ // 尝试动态获取 worker URL(仅在支持的环境中)
934
+ async function getWorkerUrl() {
935
+ if (workerUrl) {
936
+ return workerUrl;
937
+ }
938
+ try {
939
+ // 尝试使用 Vite 的 ?url 语法(仅在 Vite 环境中有效)
940
+ // @ts-ignore - Vite 特有的 ?url 语法
941
+ const workerModule = await import('modern-screenshot/worker?url');
942
+ workerUrl = workerModule.default || workerModule;
943
+ return workerUrl;
944
+ }
945
+ catch {
946
+ // Rollup 或其他构建工具不支持 ?url 语法
947
+ // modern-screenshot 会自动处理 worker URL,返回 undefined 即可
948
+ return undefined;
949
+ }
950
+ }
929
951
  /**
930
952
  * 截图管理器
931
953
  * 负责页面截图、压缩和上传功能
@@ -947,6 +969,8 @@ class ScreenshotManager {
947
969
  // WebWorker 相关
948
970
  this.worker = null;
949
971
  this.screenshotTimer = null;
972
+ // modern-screenshot Worker 上下文(用于复用,避免频繁创建和销毁)
973
+ this.screenshotContext = null;
950
974
  // PostMessage 监听器
951
975
  this.messageHandler = null;
952
976
  // 动态轮询间隔(由 iframe 消息控制)
@@ -970,7 +994,7 @@ class ScreenshotManager {
970
994
  outputFormat: options.outputFormat ?? 'webp',
971
995
  enableCORS: options.enableCORS ?? true,
972
996
  proxyUrl: options.proxyUrl ?? '',
973
- engine: options.engine ?? 'html2canvas',
997
+ engine: options.engine ?? 'modern-screenshot',
974
998
  corsMode: options.corsMode ?? 'canvas-proxy',
975
999
  silentMode: options.silentMode ?? false,
976
1000
  maxRetries: options.maxRetries ?? 2
@@ -982,6 +1006,16 @@ class ScreenshotManager {
982
1006
  * 设置目标元素
983
1007
  */
984
1008
  setTargetElement(element) {
1009
+ // 如果元素改变了,清理旧的 Worker 上下文
1010
+ if (this.targetElement !== element && this.screenshotContext) {
1011
+ try {
1012
+ modernScreenshot.destroyContext(this.screenshotContext);
1013
+ }
1014
+ catch (e) {
1015
+ // 忽略清理错误
1016
+ }
1017
+ this.screenshotContext = null;
1018
+ }
985
1019
  this.targetElement = element;
986
1020
  }
987
1021
  /**
@@ -1034,8 +1068,11 @@ class ScreenshotManager {
1034
1068
  }
1035
1069
  // 保存当前配置
1036
1070
  this.currentUploadConfig = config;
1037
- // 根据 expirationMinutes 判断是否开启截图功能
1038
- if (config.expirationMinutes > 0) {
1071
+ // 根据 ttl 判断是否开启截图功能
1072
+ // ttl == 0 表示禁用,ttl > 0 且大于当前时间表示有效
1073
+ const currentTime = Date.now();
1074
+ const isValid = config.ttl > 0 && config.ttl > currentTime;
1075
+ if (isValid) {
1039
1076
  // 启用截图功能
1040
1077
  if (!this.isEnabled) {
1041
1078
  if (!this.options.silentMode) {
@@ -1045,9 +1082,12 @@ class ScreenshotManager {
1045
1082
  }
1046
1083
  // 设置动态轮询间隔(使用 duration,单位:毫秒)
1047
1084
  this.dynamicInterval = config.duration || this.options.interval;
1085
+ // 计算剩余有效时间(毫秒)
1086
+ const remainingTime = config.ttl - currentTime;
1048
1087
  // 启动或更新截图轮询
1049
1088
  if (!this.options.silentMode) {
1050
- console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,过期时间: ${config.expirationMinutes}分钟`);
1089
+ const remainingMinutes = Math.ceil(remainingTime / 60000);
1090
+ console.log(`📸 [iframe] 设置轮询间隔: ${this.dynamicInterval}ms,剩余有效时间: ${remainingMinutes}分钟`);
1051
1091
  }
1052
1092
  // 先执行一次截图,等待完成后再上传
1053
1093
  this.takeScreenshotAndUpload(config);
@@ -1064,12 +1104,17 @@ class ScreenshotManager {
1064
1104
  this.isEnabled = false;
1065
1105
  this.currentUploadConfig = null;
1066
1106
  this.expirationTimer = null;
1067
- }, config.expirationMinutes * 60 * 1000);
1107
+ }, remainingTime);
1068
1108
  }
1069
1109
  else {
1070
- // 禁用截图功能
1110
+ // 禁用截图功能(ttl == 0 或已过期)
1071
1111
  if (!this.options.silentMode) {
1072
- console.log('📸 [iframe] expirationMinutes <= 0,禁用截图功能');
1112
+ if (config.ttl === 0) {
1113
+ console.log('📸 [iframe] ttl == 0,禁用截图功能');
1114
+ }
1115
+ else {
1116
+ console.log('📸 [iframe] ttl 已过期,禁用截图功能');
1117
+ }
1073
1118
  }
1074
1119
  this.stopScreenshot();
1075
1120
  this.isEnabled = false;
@@ -1153,9 +1198,20 @@ class ScreenshotManager {
1153
1198
  console.error('📸 [上传] 配置缺少必需字段:', config);
1154
1199
  return null;
1155
1200
  }
1201
+ // 确保 duration 存在,如果没有则使用默认值
1156
1202
  if (typeof config.duration !== 'number' || config.duration <= 0) {
1157
1203
  config.duration = this.options.interval;
1158
1204
  }
1205
+ // 确保 ttl 存在,如果没有则尝试从 expirationMinutes 转换(兼容旧格式)
1206
+ if (typeof config.ttl !== 'number') {
1207
+ if (typeof config.expirationMinutes === 'number' && config.expirationMinutes > 0) {
1208
+ // 兼容旧格式:将 expirationMinutes 转换为 ttl
1209
+ config.ttl = Date.now() + config.expirationMinutes * 60 * 1000;
1210
+ }
1211
+ else {
1212
+ config.ttl = 0; // 默认禁用
1213
+ }
1214
+ }
1159
1215
  return config;
1160
1216
  }
1161
1217
  catch (error) {
@@ -1248,10 +1304,10 @@ class ScreenshotManager {
1248
1304
  this.waitForStylesAndFonts(),
1249
1305
  this.waitForFonts()
1250
1306
  ]);
1251
- // 选择截图引擎(仅支持 html2canvas
1252
- const selectedEngine = 'html2canvas';
1307
+ // 选择截图引擎(仅支持 modern-screenshot
1308
+ const selectedEngine = 'modern-screenshot';
1253
1309
  if (!this.options.silentMode) {
1254
- console.log(`📸 使用截图引擎: ${selectedEngine}`);
1310
+ console.log(`📸 使用截图引擎: ${selectedEngine} (Worker 模式)`);
1255
1311
  }
1256
1312
  // 预处理网络图片
1257
1313
  if (this.options.enableCORS) {
@@ -1261,8 +1317,8 @@ class ScreenshotManager {
1261
1317
  let dataUrl;
1262
1318
  // 等待一小段时间,确保 DOM 更新完成
1263
1319
  await new Promise(resolve => setTimeout(resolve, 100));
1264
- // 使用 html2canvas 截图
1265
- dataUrl = await this.takeScreenshotWithHtml2Canvas(this.targetElement);
1320
+ // 使用 modern-screenshot 截图(启用 Worker)
1321
+ dataUrl = await this.takeScreenshotWithModernScreenshot(this.targetElement);
1266
1322
  const timestamp = Date.now();
1267
1323
  // 更新状态
1268
1324
  this.screenshotCount++;
@@ -1327,11 +1383,11 @@ class ScreenshotManager {
1327
1383
  }
1328
1384
  }
1329
1385
  /**
1330
- * 使用 html2canvas 截图
1386
+ * 使用 modern-screenshot 截图(启用 Worker)
1331
1387
  */
1332
- async takeScreenshotWithHtml2Canvas(element) {
1388
+ async takeScreenshotWithModernScreenshot(element) {
1333
1389
  if (!this.options.silentMode) {
1334
- console.log('📸 使用 html2canvas 引擎截图...');
1390
+ console.log('📸 使用 modern-screenshot 引擎截图(Worker 模式)...');
1335
1391
  }
1336
1392
  const { width, height } = this.calculateCompressedSize(element.scrollWidth, element.scrollHeight, this.options.maxWidth, this.options.maxHeight);
1337
1393
  const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
@@ -1339,85 +1395,164 @@ class ScreenshotManager {
1339
1395
  const mobileQuality = isMobile || isLowEndDevice ? Math.max(this.options.quality * 0.7, 0.3) : this.options.quality;
1340
1396
  const mobileWidth = isMobile ? Math.min(width, 1280) : width;
1341
1397
  const mobileHeight = isMobile ? Math.min(height, 720) : height;
1342
- const canvas = await html2canvas(element, {
1343
- useCORS: this.options.enableCORS,
1344
- allowTaint: true,
1345
- scale: isMobile ? 0.8 : this.options.scale,
1346
- backgroundColor: '#ffffff',
1347
- logging: false,
1348
- width: mobileWidth,
1349
- height: mobileHeight,
1350
- scrollX: 0,
1351
- scrollY: 0,
1352
- removeContainer: false,
1353
- foreignObjectRendering: false,
1354
- onclone: (clonedDoc) => {
1355
- const clonedImages = clonedDoc.querySelectorAll('img');
1356
- clonedImages.forEach((img) => {
1357
- if (img.src && !img.src.startsWith('data:') && !img.src.startsWith('blob:')) {
1358
- try {
1359
- const imgUrl = new URL(img.src, window.location.href);
1360
- const currentOrigin = window.location.origin;
1361
- if (this.options.proxyUrl && img.src.includes(this.options.proxyUrl.split('/api/image-proxy')[0])) {
1362
- return;
1363
- }
1364
- if (imgUrl.origin !== currentOrigin) {
1365
- if (this.options.corsMode === 'canvas-proxy') {
1366
- const cachedDataUrl = this.imageProxyCache.get(img.src);
1367
- if (cachedDataUrl) {
1368
- img.src = cachedDataUrl;
1369
- }
1370
- else if (img.crossOrigin) {
1371
- img.removeAttribute('crossOrigin');
1372
- }
1373
- }
1374
- else if (!img.crossOrigin) {
1375
- img.crossOrigin = 'anonymous';
1376
- }
1377
- }
1378
- }
1379
- catch (e) {
1380
- // URL 解析失败,跳过
1381
- }
1382
- }
1383
- });
1384
- },
1385
- ignoreElements: (element) => {
1386
- const htmlElement = element;
1387
- return element.classList.contains('van-popup') ||
1388
- element.classList.contains('van-overlay') ||
1389
- element.classList.contains('van-toast') ||
1390
- element.classList.contains('van-dialog') ||
1391
- element.classList.contains('van-loading') ||
1392
- htmlElement.style.display === 'none' ||
1393
- htmlElement.style.visibility === 'hidden';
1394
- },
1395
- imageTimeout: 15000
1396
- });
1397
- let mimeType = 'image/jpeg';
1398
- let finalQuality = mobileQuality;
1399
- if (this.options.outputFormat === 'webp' && !isMobile) {
1398
+ // 处理跨域图片的函数
1399
+ const handleCrossOriginImage = async (url) => {
1400
+ // 如果是 data URL 或 blob URL,直接返回
1401
+ if (url.startsWith('data:') || url.startsWith('blob:')) {
1402
+ return url;
1403
+ }
1404
+ // 如果是同源图片,直接返回
1400
1405
  try {
1401
- const testCanvas = document.createElement('canvas');
1402
- testCanvas.width = 1;
1403
- testCanvas.height = 1;
1404
- const testDataUrl = testCanvas.toDataURL('image/webp');
1405
- if (testDataUrl.indexOf('webp') !== -1) {
1406
- mimeType = 'image/webp';
1406
+ const imgUrl = new URL(url, window.location.href);
1407
+ if (imgUrl.origin === window.location.origin) {
1408
+ return url;
1409
+ }
1410
+ }
1411
+ catch (e) {
1412
+ // URL 解析失败,继续处理
1413
+ }
1414
+ // 如果配置了代理服务器,使用代理处理跨域图片
1415
+ if (this.options.proxyUrl && this.options.proxyUrl.trim() !== '') {
1416
+ // 检查缓存
1417
+ if (this.imageProxyCache.has(url)) {
1418
+ return this.imageProxyCache.get(url);
1419
+ }
1420
+ try {
1421
+ // 构建代理请求参数
1422
+ const params = new URLSearchParams({
1423
+ url: url,
1424
+ maxWidth: String(this.options.maxWidth || 1600),
1425
+ maxHeight: String(this.options.maxHeight || 900),
1426
+ quality: String(Math.round((this.options.quality || 0.4) * 100)),
1427
+ format: this.options.outputFormat || 'webp'
1428
+ });
1429
+ let baseUrl = this.options.proxyUrl;
1430
+ baseUrl = baseUrl.replace(/[?&]$/, '');
1431
+ const proxyUrl = `${baseUrl}?${params.toString()}`;
1432
+ // 请求代理服务器
1433
+ const response = await fetch(proxyUrl, {
1434
+ method: 'GET',
1435
+ mode: 'cors',
1436
+ credentials: 'omit',
1437
+ headers: {
1438
+ 'Accept': 'image/*'
1439
+ },
1440
+ cache: 'no-cache'
1441
+ });
1442
+ if (!response.ok) {
1443
+ throw new Error(`代理请求失败: ${response.status}`);
1444
+ }
1445
+ const blob = await response.blob();
1446
+ const dataUrl = await this.blobToDataUrl(blob);
1447
+ // 缓存结果
1448
+ this.imageProxyCache.set(url, dataUrl);
1449
+ return dataUrl;
1450
+ }
1451
+ catch (error) {
1452
+ if (!this.options.silentMode) {
1453
+ console.warn(`📸 代理处理图片失败: ${url.substring(0, 100)}...`, error);
1454
+ }
1455
+ // 失败时返回原 URL
1456
+ return url;
1407
1457
  }
1408
1458
  }
1409
- catch {
1410
- mimeType = 'image/jpeg';
1459
+ // 如果没有配置代理,尝试使用 CORS
1460
+ if (this.options.enableCORS) {
1461
+ return url;
1462
+ }
1463
+ // 默认返回原 URL
1464
+ return url;
1465
+ };
1466
+ // 如果还没有创建 Worker 上下文,则创建
1467
+ if (!this.screenshotContext) {
1468
+ const workerNumber = isMobile || isLowEndDevice ? 1 : 2;
1469
+ // 构建 createContext 配置
1470
+ const contextOptions = {
1471
+ workerNumber,
1472
+ quality: mobileQuality,
1473
+ fetchFn: handleCrossOriginImage, // 使用代理服务器处理跨域图片
1474
+ fetch: {
1475
+ requestInit: {
1476
+ cache: 'no-cache',
1477
+ },
1478
+ bypassingCache: true,
1479
+ },
1480
+ };
1481
+ // 如果指定了尺寸,添加尺寸配置
1482
+ if (mobileWidth && mobileHeight) {
1483
+ contextOptions.width = mobileWidth;
1484
+ contextOptions.height = mobileHeight;
1485
+ }
1486
+ // 如果指定了缩放比例,添加缩放配置
1487
+ if (this.options.scale !== 1) {
1488
+ contextOptions.scale = isMobile ? 0.8 : this.options.scale;
1489
+ }
1490
+ // 尝试设置 workerUrl(如果可用)
1491
+ const resolvedWorkerUrl = await getWorkerUrl();
1492
+ if (resolvedWorkerUrl) {
1493
+ contextOptions.workerUrl = resolvedWorkerUrl;
1494
+ }
1495
+ // 创建 Worker 上下文
1496
+ this.screenshotContext = await modernScreenshot.createContext(element, contextOptions);
1497
+ }
1498
+ try {
1499
+ // 使用 Worker 上下文进行截图
1500
+ const dataUrl = await modernScreenshot.domToPng(this.screenshotContext);
1501
+ // 根据输出格式转换
1502
+ if (this.options.outputFormat !== 'png') {
1503
+ // modern-screenshot 默认输出 PNG,如果需要其他格式,需要转换
1504
+ const canvas = document.createElement('canvas');
1505
+ const ctx = canvas.getContext('2d');
1506
+ if (!ctx) {
1507
+ throw new Error('无法获取 canvas context');
1508
+ }
1509
+ const img = new Image();
1510
+ await new Promise((resolve, reject) => {
1511
+ img.onload = () => {
1512
+ canvas.width = img.width;
1513
+ canvas.height = img.height;
1514
+ ctx.drawImage(img, 0, 0);
1515
+ resolve();
1516
+ };
1517
+ img.onerror = reject;
1518
+ img.src = dataUrl;
1519
+ });
1520
+ let mimeType = 'image/jpeg';
1521
+ let finalQuality = mobileQuality;
1522
+ if (this.options.outputFormat === 'webp' && !isMobile) {
1523
+ try {
1524
+ const testCanvas = document.createElement('canvas');
1525
+ testCanvas.width = 1;
1526
+ testCanvas.height = 1;
1527
+ const testDataUrl = testCanvas.toDataURL('image/webp');
1528
+ if (testDataUrl.indexOf('webp') !== -1) {
1529
+ mimeType = 'image/webp';
1530
+ }
1531
+ }
1532
+ catch {
1533
+ mimeType = 'image/jpeg';
1534
+ }
1535
+ }
1536
+ const convertedDataUrl = mimeType === 'image/png'
1537
+ ? canvas.toDataURL(mimeType)
1538
+ : canvas.toDataURL(mimeType, finalQuality);
1539
+ return convertedDataUrl;
1411
1540
  }
1541
+ return dataUrl;
1412
1542
  }
1413
- else if (this.options.outputFormat === 'png') {
1414
- mimeType = 'image/png';
1415
- finalQuality = undefined;
1543
+ catch (error) {
1544
+ // 如果截图失败,清理上下文以便下次重新创建
1545
+ if (this.screenshotContext) {
1546
+ try {
1547
+ modernScreenshot.destroyContext(this.screenshotContext);
1548
+ }
1549
+ catch (e) {
1550
+ // 忽略清理错误
1551
+ }
1552
+ this.screenshotContext = null;
1553
+ }
1554
+ throw error;
1416
1555
  }
1417
- const dataUrl = mimeType === 'image/png'
1418
- ? canvas.toDataURL(mimeType)
1419
- : canvas.toDataURL(mimeType, finalQuality);
1420
- return dataUrl;
1421
1556
  }
1422
1557
  /**
1423
1558
  * 预处理网络图片
@@ -1530,7 +1665,7 @@ class ScreenshotManager {
1530
1665
  throw new Error(`代理请求失败: ${response.status} ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`);
1531
1666
  }
1532
1667
  const blob = await response.blob();
1533
- // 将 blob 转换为 data URL(用于 html2canvas 兼容性)
1668
+ // 将 blob 转换为 data URL(用于 modern-screenshot 兼容性)
1534
1669
  const dataUrl = await this.blobToDataUrl(blob);
1535
1670
  if (!this.options.silentMode) {
1536
1671
  console.log(`📸 ✅ 代理模式成功(已转换为 data URL): ${imageUrl.substring(0, 100)}...`);
@@ -1660,7 +1795,9 @@ class ScreenshotManager {
1660
1795
  newWorker.onerror = (e) => {
1661
1796
  console.error('📸 WebWorker 错误:', e);
1662
1797
  };
1663
- URL.revokeObjectURL(workerUrl);
1798
+ // 注意:不要立即 revokeObjectURL,因为 Worker 需要这个 URL 保持有效
1799
+ // 在 destroy() 方法中清理 Worker 时再 revoke
1800
+ // URL.revokeObjectURL(workerUrl) // 已移除,在 destroy 时清理
1664
1801
  return newWorker;
1665
1802
  }
1666
1803
  catch (err) {
@@ -1791,6 +1928,16 @@ class ScreenshotManager {
1791
1928
  this.worker.terminate();
1792
1929
  this.worker = null;
1793
1930
  }
1931
+ // 清理 modern-screenshot Worker 上下文
1932
+ if (this.screenshotContext) {
1933
+ try {
1934
+ modernScreenshot.destroyContext(this.screenshotContext);
1935
+ }
1936
+ catch (e) {
1937
+ // 忽略清理错误
1938
+ }
1939
+ this.screenshotContext = null;
1940
+ }
1794
1941
  if (this.expirationTimer) {
1795
1942
  clearTimeout(this.expirationTimer);
1796
1943
  this.expirationTimer = null;
@@ -1800,6 +1947,8 @@ class ScreenshotManager {
1800
1947
  this.messageHandler = null;
1801
1948
  }
1802
1949
  this.removeGlobalErrorHandlers();
1950
+ // 清理图片代理缓存
1951
+ this.imageProxyCache.clear();
1803
1952
  }
1804
1953
  /**
1805
1954
  * 获取状态