@h-ai/feedback 0.1.0-alpha.73 → 0.1.0-alpha.75

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bundle/feedback-bundle-viewer.ts","../src/bundle/feedback-bundle-functions.ts"],"names":["offset","strToU8"],"mappings":"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","file":"chunk-KGMLTOMM.js","sourcesContent":["import { strToU8 } from 'fflate'\n\ndeclare const __FEEDBACK_REPLAY_SCRIPT__: string\n\n/** 查看器只使用 textContent 与受限图片,不执行原应用或用户附件脚本。 */\nconst VIEWER_SCRIPT = `\nconst messages = {\n zh: {title:'问题反馈',facts:'采集事实',user:'用户描述',evidence:'证据',attachments:'截图与附件',missing:'缺失材料',history:'处理记录',error:'问题包读取失败',all:'全部',next:'下一页',previous:'上一页',download:'下载',empty:'未填写',replay:'页面回放',play:'播放',pause:'暂停',unavailable:'回放不可用,已保留原始证据',boundary:'回放展示采集的页面快照与交互,不执行原应用脚本。未内嵌的外部图片、字体和样式被离线策略阻止;缺失记录见下方。'},\n en: {title:'Feedback report',facts:'Collected facts',user:'User description',evidence:'Evidence',attachments:'Screenshots and attachments',missing:'Missing evidence',history:'Processing history',error:'Unable to read the bundle',all:'All',next:'Next',previous:'Previous',download:'Download',empty:'Not provided',replay:'Page replay',play:'Play',pause:'Pause',unavailable:'Replay unavailable; original evidence is preserved',boundary:'Replay shows captured snapshots and interactions without running application scripts. External images, fonts and styles that were not embedded are blocked by offline policy. See missing evidence below.'},\n ja: {title:'問題フィードバック',facts:'収集した事実',user:'ユーザーの説明',evidence:'証拠',attachments:'スクリーンショットと添付',missing:'不足資料',history:'処理記録',error:'パッケージを読み込めません',all:'すべて',next:'次へ',previous:'前へ',download:'ダウンロード',empty:'未入力',replay:'ページ再生',play:'再生',pause:'一時停止',unavailable:'再生できません。元の証拠は保持されています',boundary:'収集したスナップショットと操作を再生し、元のアプリのスクリプトは実行しません。埋め込まれていない外部画像、フォント、スタイルはオフライン方針で遮断されます。不足資料も確認してください。'}\n};\nconst language = navigator.language.startsWith('ja') ? 'ja' : navigator.language.startsWith('zh') ? 'zh' : 'en';\nconst m = messages[language];\nfunction text(tag,value,parent){const node=document.createElement(tag);node.textContent=String(value??'');parent.append(node);return node;}\nfunction section(title){const block=document.createElement('section');text('h2',title,block);document.querySelector('main').append(block);return block;}\nfunction safeImage(file){return ['image/png','image/jpeg','image/webp'].includes(file.contentType);}\nasync function load(path){const response=await fetch('../'+path);if(!response.ok)throw Error('Missing file');return response.json();}\ntry {\n const [manifest,report,evidence,history]=await Promise.all([load('manifest.json'),load('report.json'),load('evidence/records.json'),load('evidence/history.json')]);\n text('h1',m.title+' '+(report.number||report.id),document.querySelector('header'));\n text('pre',JSON.stringify(report,null,2),section(m.facts));\n text('p',report.description||m.empty,section(m.user));\n const attachments=section(m.attachments);\n for(const file of manifest.files.filter(item=>item.kind==='attachment')){\n if(!/^attachments\\\\/[\\\\w-]+\\\\.(png|jpg|webp|webm|mp4|txt|json|bin)$/.test(file.path))continue;\n const figure=document.createElement('figure');attachments.append(figure);text('figcaption',file.name||file.attachmentId,figure);\n if(safeImage(file)){const image=document.createElement('img');image.src='../'+file.path;image.alt=file.name||'';image.loading='lazy';figure.append(image);}\n if(['video/webm','video/mp4'].includes(file.contentType)){const video=document.createElement('video');video.src='../'+file.path;video.controls=true;video.preload='metadata';video.style.maxWidth='100%';figure.append(video);}\n const link=text('a',m.download,figure);link.href='../'+file.path;link.download=file.name||file.path.split('/').pop();\n }\n const replayEvents=evidence.filter(item=>item.kind==='replay'&&item.data&&item.data.event).map(item=>item.data.event).sort((a,b)=>a.timestamp-b.timestamp);\n\n if(replayEvents.length){\n const replay=section(m.replay);text('p',m.boundary,replay);\n try{\n await import('./replay.js');\n if(typeof globalThis.__HAI_FEEDBACK_REPLAY__!=='function')throw Error('Replay unavailable');\n const fullSnapshot=replayEvents.find(event=>event.type===2);\n if(!fullSnapshot)throw Error('Replay full snapshot unavailable');\n const target=document.createElement('div');replay.append(target);\n let player;\n const origin=replayEvents[0].timestamp;\n const duration=Math.max(0,replayEvents.at(-1).timestamp-origin);\n const snapshotOffset=Math.max(0,fullSnapshot.timestamp-origin);\n const play=text('button',m.play,replay);const pause=text('button',m.pause,replay);\n const slider=document.createElement('input');slider.type='range';slider.min='0';slider.max=String(Math.max(1,duration));slider.value='0';slider.setAttribute('aria-label',m.replay);replay.append(slider);\n let current=0;let playing=false;let frame=0;\n function position(value){return Math.max(0,Math.min(duration,Number.isFinite(value)?value:0));}\n function stop(){if(frame)cancelAnimationFrame(frame);frame=0;}\n // 每次定位重建实例,隔离旧回放末尾延迟到达的 finish,避免覆盖新的进度。\n function construct(){const instance=globalThis.__HAI_FEEDBACK_REPLAY__(replayEvents,target);player=instance;instance.on('finish',()=>{if(instance!==player||!playing)return;playing=false;stop();current=duration;slider.value=String(current);});}\n function update(){if(!playing)return;current=position(player.getCurrentTime());slider.value=String(current);frame=requestAnimationFrame(update);}\n // rrweb 仅同步应用严格早于偏移的事件;增加 1ms 使精确事件时间与首帧边界都包含在内。\n function seek(value){playing=false;stop();const requested=position(value);player?.destroy();construct();player.pause(Math.max(requested,snapshotOffset)+1);current=requested;slider.value=String(current);}\n\n play.onclick=()=>{stop();current=position(Number(slider.value));if(current>=duration)seek(0);playing=true;player.play(Math.max(current,snapshotOffset));update();};\n pause.onclick=()=>{player.pause();playing=false;stop();current=position(player.getCurrentTime());slider.value=String(current);};\n slider.oninput=()=>seek(Number(slider.value));\n window.addEventListener('pagehide',()=>{playing=false;stop();player.destroy();},{once:true});\n seek(0);\n }catch{text('p',m.unavailable,replay);}\n }\n const block=section(m.evidence);const filter=document.createElement('select');block.append(filter);const all=text('option',m.all,filter);all.value='';\n for(const kind of [...new Set(evidence.map(item=>item.kind))]){const option=text('option',kind,filter);option.value=kind;}\n const request=document.createElement('input');request.placeholder='requestId';request.setAttribute('aria-label','requestId');block.append(request);\n const output=text('pre','',block);const previous=text('button',m.previous,block);const next=text('button',m.next,block);const counter=text('span','',block);let page=1;\n function render(){const rows=evidence.filter(item=>(!filter.value||item.kind===filter.value)&&(!request.value||item.requestId===request.value));const pages=Math.max(1,Math.ceil(rows.length/20));page=Math.min(page,pages);output.textContent=JSON.stringify(rows.slice((page-1)*20,page*20),null,2);counter.textContent=' '+page+' / '+pages+' ('+rows.length+')';previous.disabled=page<=1;next.disabled=page>=pages;}\n filter.onchange=()=>{page=1;render();};request.oninput=()=>{page=1;render();};previous.onclick=()=>{page--;render();};next.onclick=()=>{page++;render();};render();\n text('pre',JSON.stringify(history,null,2),section(m.history));text('pre',manifest.missing.join('\\\\n')||'—',section(m.missing));\n} catch {text('p',m.error,document.querySelector('main'));}\n`\n\n/**\n * 包内可信查看器资源,CLI 从内置资源提供代码,绝不执行导入包自带的任意脚本。\n * @example 模块内部上下文\n * ```ts\n * const html = feedbackViewerFiles()['viewer/index.html']\n * const source: string = new TextDecoder().decode(html)\n * ```\n */\nexport function feedbackViewerFiles(): Record<string, Uint8Array> {\n return {\n 'viewer/index.html': strToU8(`<!doctype html><html><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; media-src 'self' blob:; connect-src 'self'; frame-src 'self' about: blob:; font-src 'self' data:; base-uri 'none'; form-action 'none'\"><title>Feedback</title><link rel=\"stylesheet\" href=\"style.css\"></head><body><header></header><main></main><script type=\"module\" src=\"app.js\"></script></body></html>`),\n 'viewer/style.css': strToU8('body{font:15px system-ui,sans-serif;line-height:1.6;margin:0;background:#f5f6f8;color:#172033}header,main{max-width:1080px;margin:auto;padding:24px}section{background:white;padding:24px;margin-bottom:20px;border:1px solid #dce1e8;border-radius:12px}h1{font-size:26px}h2{font-size:19px;margin-top:0}pre{white-space:pre-wrap;overflow-wrap:anywhere;font:13px/1.6 ui-monospace,monospace}img{max-width:100%;height:auto;border:1px solid #dce1e8}figure{margin:16px 0}input,select,button{font:inherit;padding:8px;margin:4px;border:1px solid #ccd2dc;border-radius:6px}button{cursor:pointer}a{display:block;color:#215dc0}'),\n 'viewer/app.js': strToU8(VIEWER_SCRIPT),\n 'viewer/replay.js': strToU8(typeof __FEEDBACK_REPLAY_SCRIPT__ === 'string' ? __FEEDBACK_REPLAY_SCRIPT__ : '/* Replay is available in built package artifacts. */'),\n }\n}\n","import type { HaiResult } from '@h-ai/core'\nimport type { FeedbackBundle, FeedbackBundleEvidence, FeedbackBundleEvidencePage, FeedbackBundleFile, FeedbackBundleInput, FeedbackBundleManifest, FeedbackBundleQuery, FeedbackBundleReadOptions } from './feedback-bundle-types.js'\nimport { core, err, HaiCommonError, ok } from '@h-ai/core'\nimport { strFromU8, strToU8, unzipSync, zipSync } from 'fflate'\nimport { feedbackViewerFiles } from './feedback-bundle-viewer.js'\n\nconst bundleM = core.i18n.createMessageGetter({\n 'zh-CN': { invalid: '问题包格式、容量或完整性校验失败', title: '问题反馈', facts: '采集事实', missing: '缺失材料', user: '用户描述', empty: '未填写', evidence: '证据', attachments: '附件' },\n 'en-US': { invalid: 'The feedback bundle failed format, size or integrity validation', title: 'Feedback report', facts: 'Collected facts', missing: 'Missing evidence', user: 'User description', empty: 'Not provided', evidence: 'Evidence', attachments: 'Attachments' },\n 'ja-JP': { invalid: '問題パッケージの形式、容量または整合性の検証に失敗しました', title: '問題フィードバック', facts: '収集した事実', missing: '不足している資料', user: 'ユーザーの説明', empty: '未入力', evidence: '証拠', attachments: '添付ファイル' },\n})\n\nconst MAX_FILES = 1024\nconst MAX_BYTES = 64 * 1024 * 1024\nconst MAX_FILE_BYTES = 16 * 1024 * 1024\nconst SHA256 = /^[a-f0-9]{64}$/\nconst SAFE_ID = /^[\\w-]{1,128}$/\n\n/** JSON 仅做数据边界,禁止保留原型和可执行值。 */\nfunction jsonObject(value: unknown): Record<string, unknown> {\n const parsed: unknown = JSON.parse(JSON.stringify(value))\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))\n throw new Error('Expected object')\n return parsed as Record<string, unknown>\n}\n\nfunction safePath(value: string): boolean {\n return /^[a-z0-9][\\w./-]*$/i.test(value) && !value.endsWith('/')\n && !value.split('/').some(segment => !segment || segment === '.' || segment === '..')\n}\n\nasync function checksum(bytes: Uint8Array): Promise<string> {\n const hash = await globalThis.crypto.subtle.digest('SHA-256', new Uint8Array(bytes).buffer)\n return Array.from(new Uint8Array(hash), byte => byte.toString(16).padStart(2, '0')).join('')\n}\n\nfunction objectFromFile(files: Readonly<Record<string, Uint8Array>>, path: string): Record<string, unknown> {\n const bytes = files[path]\n if (!bytes)\n throw new Error('Missing file')\n const parsed: unknown = JSON.parse(strFromU8(bytes))\n return jsonObject(parsed)\n}\n\nfunction evidenceFrom(value: unknown): FeedbackBundleEvidence {\n const record = jsonObject(value)\n if (typeof record.source !== 'string' || typeof record.kind !== 'string' || typeof record.timestamp !== 'number' || !Number.isFinite(record.timestamp))\n throw new Error('Invalid evidence')\n for (const key of ['id', 'requestId', 'errorId', 'missingReason']) {\n if (record[key] !== undefined && typeof record[key] !== 'string')\n throw new Error('Invalid evidence field')\n }\n if (record.sequence !== undefined && (typeof record.sequence !== 'number' || !Number.isSafeInteger(record.sequence) || record.sequence < 0))\n throw new Error('Invalid evidence sequence')\n return {\n source: record.source,\n kind: record.kind,\n timestamp: record.timestamp,\n ...(typeof record.id === 'string' ? { id: record.id } : {}),\n ...(typeof record.sequence === 'number' ? { sequence: record.sequence } : {}),\n ...(typeof record.requestId === 'string' ? { requestId: record.requestId } : {}),\n ...(typeof record.errorId === 'string' ? { errorId: record.errorId } : {}),\n ...(typeof record.missingReason === 'string' ? { missingReason: record.missingReason } : {}),\n ...(record.data !== undefined ? { data: record.data } : {}),\n }\n}\n\nfunction limitsFor(options: FeedbackBundleReadOptions = {}) {\n const limits = { maxFiles: options.maxFiles ?? MAX_FILES, maxBytes: options.maxBytes ?? MAX_BYTES, maxFileBytes: options.maxFileBytes ?? MAX_FILE_BYTES }\n if (Object.values(limits).some(value => !Number.isSafeInteger(value) || value <= 0))\n throw new Error('Invalid limits')\n return limits\n}\n\n/** 先检查 ZIP 中央目录,避免解压后才发现重复路径、符号链接或压缩炸弹。 */\nfunction preflight(bytes: Uint8Array, limits: ReturnType<typeof limitsFor>): void {\n if (bytes.byteLength > limits.maxBytes || bytes.byteLength < 22)\n throw new Error('Invalid archive size')\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)\n let end = -1\n for (let offset = bytes.length - 22; offset >= Math.max(0, bytes.length - 65557); offset--) {\n if (view.getUint32(offset, true) === 0x06054B50 && offset + 22 + view.getUint16(offset + 20, true) === bytes.length) {\n end = offset\n break\n }\n }\n if (end < 0 || view.getUint16(end + 4, true) !== 0 || view.getUint16(end + 6, true) !== 0)\n throw new Error('Invalid archive directory')\n const count = view.getUint16(end + 10, true)\n const size = view.getUint32(end + 12, true)\n let offset = view.getUint32(end + 16, true)\n if (count === 0 || count > limits.maxFiles || count !== view.getUint16(end + 8, true) || offset + size !== end)\n throw new Error('Invalid archive directory size')\n let total = 0\n const names = new Set<string>()\n for (let index = 0; index < count; index++) {\n if (offset + 46 > end || view.getUint32(offset, true) !== 0x02014B50)\n throw new Error('Invalid archive entry')\n const nameLength = view.getUint16(offset + 28, true)\n const next = offset + 46 + nameLength + view.getUint16(offset + 30, true) + view.getUint16(offset + 32, true)\n if (next > end)\n throw new Error('Invalid archive entry length')\n const name = strFromU8(bytes.subarray(offset + 46, offset + 46 + nameLength))\n const originalSize = view.getUint32(offset + 24, true)\n const method = view.getUint16(offset + 10, true)\n const mode = (view.getUint32(offset + 38, true) >>> 16) & 0xF000\n if (!safePath(name) || names.has(name.toLowerCase()) || originalSize > limits.maxFileBytes\n || (view.getUint16(offset + 8, true) & 1) || ![0, 8].includes(method) || (mode !== 0 && mode !== 0x8000)) {\n throw new Error('Unsafe archive entry')\n }\n total += originalSize\n if (total > limits.maxBytes)\n throw new Error('Archive expansion limit')\n names.add(name.toLowerCase())\n offset = next\n }\n if (offset !== end)\n throw new Error('Unexpected archive entry')\n}\n\nfunction parseManifest(value: Record<string, unknown>): FeedbackBundleManifest {\n if (value.format !== 'hai-feedback' || value.version !== 1 || typeof value.reportId !== 'string'\n || typeof value.evidenceRevision !== 'number' || !Number.isSafeInteger(value.evidenceRevision) || value.evidenceRevision < 0\n || typeof value.createdAt !== 'number' || !Number.isFinite(value.createdAt) || !Array.isArray(value.files)\n || !Array.isArray(value.missing) || value.missing.some(item => typeof item !== 'string')) {\n throw new Error('Unsupported manifest')\n }\n const files: FeedbackBundleFile[] = value.files.map((item) => {\n const file = jsonObject(item)\n if (typeof file.path !== 'string' || !safePath(file.path) || file.path === 'manifest.json'\n || typeof file.size !== 'number' || !Number.isSafeInteger(file.size) || file.size < 0\n || typeof file.sha256 !== 'string' || !SHA256.test(file.sha256)\n || !['report', 'evidence', 'history', 'attachment', 'summary', 'viewer'].includes(String(file.kind))) {\n throw new Error('Invalid manifest file')\n }\n return {\n path: file.path,\n size: file.size,\n sha256: file.sha256,\n kind: file.kind as FeedbackBundleFile['kind'],\n ...(typeof file.attachmentId === 'string' ? { attachmentId: file.attachmentId } : {}),\n ...(typeof file.name === 'string' ? { name: file.name } : {}),\n ...(typeof file.contentType === 'string' ? { contentType: file.contentType } : {}),\n }\n })\n if (new Set(files.map(file => file.path)).size !== files.length)\n throw new Error('Duplicate manifest file')\n return { format: 'hai-feedback', version: 1, reportId: value.reportId, evidenceRevision: value.evidenceRevision, createdAt: value.createdAt, missing: value.missing as string[], files }\n}\n\n/**\n * 生成含摘要、证据索引、附件与静态查看器的 ZIP;调用前应完成授权与脱敏。\n * @example\n * ```ts\n * import { createFeedbackBundle } from '@h-ai/feedback/bundle'\n * const result = await createFeedbackBundle({ report: { id: 'fb_1' }, evidence: [] })\n * if (result.success) { const bytes: Uint8Array = result.data }\n * ```\n */\nexport async function createFeedbackBundle<TReport extends { id: string }>(input: FeedbackBundleInput<TReport>): Promise<HaiResult<Uint8Array>> {\n try {\n if (input.createdAt !== undefined && (!Number.isSafeInteger(input.createdAt) || input.createdAt < 0))\n throw new Error('Invalid bundle creation time')\n const report = jsonObject(input.report)\n if (typeof report.id !== 'string' || !SAFE_ID.test(report.id))\n throw new Error('Invalid report')\n if (['appVersion', 'buildId', 'commit'].some(key => report[key] !== undefined && (typeof report[key] !== 'string' || report[key].length > 128)))\n throw new Error('Invalid build metadata')\n if (report.evidenceRevision !== undefined && (typeof report.evidenceRevision !== 'number' || !Number.isSafeInteger(report.evidenceRevision) || report.evidenceRevision < 0))\n throw new Error('Invalid evidence revision')\n const evidence = input.evidence.map(evidenceFrom)\n const history = (input.history ?? []).map(jsonObject)\n const missing = [...(input.missing ?? [])]\n if (missing.some(item => typeof item !== 'string'))\n throw new Error('Invalid missing evidence')\n const files: Record<string, Uint8Array> = {\n 'report.json': strToU8(JSON.stringify(report)),\n 'timeline.ndjson': strToU8(evidence.map(record => JSON.stringify(record)).join('\\n')),\n 'evidence/records.json': strToU8(JSON.stringify(evidence)),\n 'evidence/history.json': strToU8(JSON.stringify(history)),\n ...feedbackViewerFiles(),\n }\n const manifestFiles: FeedbackBundleFile[] = []\n const ids = new Set<string>()\n for (const attachment of input.attachments ?? []) {\n if (typeof attachment.id !== 'string' || attachment.id.length < 1 || attachment.id.length > 128 || ids.has(attachment.id) || attachment.bytes.byteLength > MAX_FILE_BYTES)\n throw new Error('Invalid attachment')\n ids.add(attachment.id)\n const suffix = ({ 'image/png': 'png', 'image/jpeg': 'jpg', 'image/webp': 'webp', 'video/webm': 'webm', 'video/mp4': 'mp4', 'text/plain': 'txt', 'application/json': 'json', 'application/pdf': 'pdf' } as Record<string, string>)[attachment.contentType] ?? 'bin'\n // 原始标识仅保存在清单,使用区分大小写且保留字符串编码的摘要构造安全路径。\n const path = `attachments/${await checksum(strToU8(JSON.stringify(attachment.id)))}.${suffix}`\n const hash = await checksum(attachment.bytes)\n if (attachment.checksum && attachment.checksum !== hash)\n throw new Error('Attachment checksum mismatch')\n files[path] = new Uint8Array(attachment.bytes)\n manifestFiles.push({ path, size: attachment.bytes.byteLength, sha256: hash, kind: 'attachment', attachmentId: attachment.id, name: attachment.name, contentType: attachment.contentType })\n }\n const manifest: FeedbackBundleManifest = { format: 'hai-feedback', version: 1, reportId: report.id, evidenceRevision: typeof report.evidenceRevision === 'number' ? report.evidenceRevision : 0, createdAt: input.createdAt ?? Date.now(), missing, files: manifestFiles }\n const temporary: FeedbackBundle = { report: { ...report, id: report.id }, evidence, history, manifest, files }\n files['summary.md'] = strToU8(summarizeFeedbackBundle(temporary))\n for (const [path, bytes] of Object.entries(files)) {\n if (manifestFiles.some(file => file.path === path))\n continue\n const kind = path === 'report.json' ? 'report' : path === 'summary.md' ? 'summary' : path.startsWith('viewer/') ? 'viewer' : path.endsWith('history.json') ? 'history' : 'evidence'\n manifest.files.push({ path, size: bytes.byteLength, sha256: await checksum(bytes), kind })\n }\n files['manifest.json'] = strToU8(JSON.stringify(manifest, null, 2))\n const total = Object.values(files).reduce((sum, file) => sum + file.byteLength, 0)\n if (Object.keys(files).length > MAX_FILES || total > Math.min(input.maxBytes ?? MAX_BYTES, MAX_BYTES) || Object.values(files).some(file => file.byteLength > MAX_FILE_BYTES))\n throw new Error('Bundle limits exceeded')\n return ok(zipSync(files, { level: 1, mtime: new Date(1980, 0, 1) }))\n }\n catch {\n return err(HaiCommonError.VALIDATION_ERROR, bundleM('invalid'))\n }\n}\n\n/**\n * 校验 ZIP 路径、容量、协议与所有文件的 SHA-256 后读取;不执行包内代码。\n * @example\n * ```ts\n * import { createFeedbackBundle, readFeedbackBundle } from '@h-ai/feedback/bundle'\n * const created = await createFeedbackBundle({ report: { id: 'fb_1' }, evidence: [] })\n * if (created.success) {\n * const parsed = await readFeedbackBundle(created.data, { maxBytes: 32 * 1024 * 1024 })\n * if (parsed.success) { const reportId: string = parsed.data.report.id }\n * }\n * ```\n */\nexport async function readFeedbackBundle(bytes: Uint8Array, options?: FeedbackBundleReadOptions): Promise<HaiResult<FeedbackBundle>> {\n try {\n const limits = limitsFor(options)\n preflight(bytes, limits)\n const files = unzipSync(bytes)\n const manifest = parseManifest(objectFromFile(files, 'manifest.json'))\n if (Object.keys(files).length !== manifest.files.length + 1)\n throw new Error('Unexpected bundle file')\n let total = 0\n for (const file of manifest.files) {\n const content = files[file.path]\n if (!content || content.byteLength !== file.size || content.byteLength > limits.maxFileBytes || await checksum(content) !== file.sha256)\n throw new Error('File integrity failed')\n total += content.byteLength\n }\n if (total > limits.maxBytes)\n throw new Error('Bundle expansion limit')\n const report = objectFromFile(files, 'report.json')\n if (['appVersion', 'buildId', 'commit'].some(key => report[key] !== undefined && (typeof report[key] !== 'string' || report[key].length > 128)))\n throw new Error('Invalid build metadata')\n if (typeof report.id !== 'string' || report.id !== manifest.reportId)\n throw new Error('Report mismatch')\n const records: unknown = JSON.parse(strFromU8(files['evidence/records.json'] ?? new Uint8Array()))\n const history: unknown = JSON.parse(strFromU8(files['evidence/history.json'] ?? new Uint8Array()))\n if (!Array.isArray(records) || !Array.isArray(history))\n throw new Error('Invalid evidence collection')\n return ok({ manifest, report: { ...report, id: report.id }, evidence: records.map(evidenceFrom), history: history.map(jsonObject), files })\n }\n catch {\n return err(HaiCommonError.VALIDATION_ERROR, bundleM('invalid'))\n }\n}\n\n/**\n * 生成人工与 AI 可读摘要,明确用户描述与采集事实。\n * @example\n * ```ts\n * import { createFeedbackBundle, readFeedbackBundle, summarizeFeedbackBundle } from '@h-ai/feedback/bundle'\n * const created = await createFeedbackBundle({ report: { id: 'fb_1' }, evidence: [] })\n * if (created.success) {\n * const parsed = await readFeedbackBundle(created.data)\n * if (parsed.success) { const markdown: string = summarizeFeedbackBundle(parsed.data) }\n * }\n * ```\n */\nexport function summarizeFeedbackBundle(bundle: FeedbackBundle): string {\n const report = bundle.report\n const safeText = (value: unknown) => typeof value === 'string' || typeof value === 'number' ? String(value).replaceAll('\\r', '').replaceAll('\\n', ' ') : ''\n return [\n `# ${bundleM('title')} ${safeText(report.number ?? report.id)}`,\n '',\n `## ${bundleM('user')}`,\n '',\n safeText(report.description) || bundleM('empty'),\n '',\n `## ${bundleM('facts')}`,\n '',\n `- ID: ${safeText(report.id)}`,\n `- App: ${safeText(report.appId)} ${safeText(report.appVersion)}`,\n `- Build: ${safeText(report.buildId)} ${safeText(report.commit)}`,\n `- Revision: ${bundle.manifest.evidenceRevision}`,\n `- ${bundleM('evidence')}: ${bundle.evidence.length}`,\n `- ${bundleM('attachments')}: ${bundle.manifest.files.filter(file => file.kind === 'attachment').length}`,\n '',\n `## ${bundleM('missing')}`,\n '',\n ...bundle.manifest.missing.map(reason => `- ${safeText(reason)}`),\n '',\n ].join('\\n')\n}\n\n/**\n * 通过时间、请求、错误与类型筛选离线证据;错误按锚点来源和请求取前后各 100 条,分页最大 100 条。\n * @example\n * ```ts\n * import { createFeedbackBundle, queryFeedbackBundle, readFeedbackBundle } from '@h-ai/feedback/bundle'\n * const created = await createFeedbackBundle({ report: { id: 'fb_1' }, evidence: [] })\n * if (created.success) {\n * const parsed = await readFeedbackBundle(created.data)\n * if (parsed.success) { const page = queryFeedbackBundle(parsed.data, { requestId: 'req_1', page: 1, pageSize: 20 }) }\n * }\n * ```\n */\nexport function queryFeedbackBundle(bundle: FeedbackBundle, query: FeedbackBundleQuery = {}): FeedbackBundleEvidencePage {\n const page = Number.isSafeInteger(query.page) && (query.page ?? 0) > 0 ? query.page! : 1\n const pageSize = Number.isSafeInteger(query.pageSize) && (query.pageSize ?? 0) > 0 ? Math.min(100, query.pageSize!) : 20\n let candidates = bundle.evidence\n if (query.errorId) {\n const anchor = candidates.find(item => item.kind === 'error' && item.errorId === query.errorId)\n if (!anchor)\n return { items: [], total: 0, page, pageSize }\n const anchorSequence = anchor.sequence ?? anchor.timestamp\n const context = candidates.filter(item => item.source === anchor.source && item.requestId === anchor.requestId && ['log', 'error'].includes(item.kind))\n const before = context.filter(item => (item.sequence ?? item.timestamp) <= anchorSequence).sort((left, right) => (right.sequence ?? right.timestamp) - (left.sequence ?? left.timestamp)).slice(0, 101)\n const after = context.filter(item => (item.sequence ?? item.timestamp) > anchorSequence).sort((left, right) => (left.sequence ?? left.timestamp) - (right.sequence ?? right.timestamp)).slice(0, 100)\n const window = new Set([...before, ...after])\n candidates = candidates.filter(item => window.has(item))\n }\n const records = candidates.filter(item => (!query.kind || item.kind === query.kind)\n && (!query.requestId || item.requestId === query.requestId)\n && (query.from === undefined || item.timestamp >= query.from) && (query.to === undefined || item.timestamp <= query.to))\n .sort((left, right) => left.timestamp - right.timestamp || left.source.localeCompare(right.source) || (left.sequence ?? 0) - (right.sequence ?? 0))\n return { items: records.slice((page - 1) * pageSize, page * pageSize), total: records.length, page, pageSize }\n}\n\n/**\n * 获取内置可信离线查看器;本地服务必须使用此资源而不是执行导入包中的脚本。\n * @example\n * ```ts\n * import { getFeedbackBundleViewerFiles } from '@h-ai/feedback/bundle'\n * const html: Uint8Array | undefined = getFeedbackBundleViewerFiles()['viewer/index.html']\n * ```\n */\nexport function getFeedbackBundleViewerFiles(): Readonly<Record<string, Uint8Array>> {\n return feedbackViewerFiles()\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { a as FeedbackSaveResult } from '../feedback-client-files-B88nCOo_.js';
2
2
  export { F as FeedbackFileSaver, c as configureFeedbackSaving, f as feedbackDataBytes, s as saveFeedbackFile } from '../feedback-client-files-B88nCOo_.js';
3
- import { FeedbackBudget, FeedbackEvidenceInput, FeedbackSubmitInput, FeedbackReport, FeedbackAppendEvidenceInput, FeedbackCompleteInput, FeedbackUploadInput, FeedbackAttachmentInput, FeedbackDetail, FeedbackEvidenceQuery, FeedbackEvidence, FeedbackExportInput, FeedbackJob, FeedbackAttachmentData } from '@h-ai/api-contract/feedback';
3
+ import { FeedbackBudget, FeedbackEvidenceInput, FeedbackSubmitInput, FeedbackReport, FeedbackAppendEvidenceInput, FeedbackCompleteInput, FeedbackUploadInput, FeedbackAttachmentInput, FeedbackDetail, FeedbackEvidenceQuery, FeedbackEvidence, FeedbackExportInput, FeedbackJob, FeedbackAttachmentData, FeedbackRetryInput } from '@h-ai/api-contract/feedback';
4
4
  import * as _h_ai_core from '@h-ai/core';
5
5
  import { HaiResult, PaginatedResult } from '@h-ai/core';
6
6
 
@@ -80,12 +80,18 @@ interface FeedbackClientConfig {
80
80
  actions: FeedbackClientActions;
81
81
  cookieAllowlist?: readonly string[];
82
82
  screenshot?: boolean;
83
- captureScreenshot?: () => Promise<Uint8Array>;
83
+ /** 自定义截图可响应取消信号;忽略取消时仍等待实际任务退出后才释放单飞锁。 */
84
+ captureScreenshot?: (options?: {
85
+ signal: AbortSignal;
86
+ }) => Promise<Uint8Array>;
84
87
  screenshotTimeoutMs?: number;
88
+ /** 自动关键截图显式开启;默认仅在用户准备反馈时截图。 */
85
89
  keyScreenshots?: boolean;
86
90
  maxKeyScreenshots?: number;
87
91
  keyScreenshotThrottleMs?: number;
88
92
  replay?: boolean;
93
+ /** 默认 prepare 时启动 DOM 回放;init 模式用于宿主明确需要全程回溯的场景。 */
94
+ replayStart?: 'init' | 'prepare';
89
95
  /** 原生 console 采集显式启用;不改变输出级别或默认采集全部 debug。 */
90
96
  captureConsole?: boolean;
91
97
  persistDraft?: boolean;
@@ -160,6 +166,8 @@ interface FeedbackBrowserClient {
160
166
  /** URL 按附件修订复用,删除、替换和会话关闭时释放。 */
161
167
  getView: () => FeedbackDraftView;
162
168
  releasePreviews: () => void;
169
+ /** 关闭反馈界面时暂停 DOM 回放和截图;保留轻量日志、草稿及已受理上传。 */
170
+ pause: () => void;
163
171
  /** 导出并使用当前平台的保存/分享入口。 */
164
172
  saveDraft: (input?: FeedbackClientSubmitInput) => Promise<HaiResult<FeedbackSaveResult>>;
165
173
  /** 并发初始化返回 INIT_IN_PROGRESS;重初始化先等待旧会话关闭。 */
@@ -240,6 +248,7 @@ interface FeedbackReviewActions {
240
248
  id: string;
241
249
  jobId: string;
242
250
  }) => Promise<HaiResult<FeedbackAttachmentData>>;
251
+ retry: (input: FeedbackRetryInput) => Promise<HaiResult<unknown>>;
243
252
  }
244
253
  /**
245
254
  * 创建可取消的详情动作;退出账号调用 close,旧轮询不能继续下载到新会话。
@@ -256,6 +265,7 @@ interface FeedbackReviewActions {
256
265
  */
257
266
  declare function createFeedbackReview(actions: FeedbackReviewActions): {
258
267
  close(): void;
268
+ retryReport(id: string): Promise<HaiResult<void>>;
259
269
  loadReplay(id: string): Promise<HaiResult<FeedbackEvidence[]>>;
260
270
  exportReport(id: string): Promise<{
261
271
  success: false;
@@ -1,4 +1,4 @@
1
- import { feedbackM, HaiFeedbackError, redactFeedbackText } from '../chunk-PYKGS35A.js';
1
+ import { feedbackM, HaiFeedbackError, redactFeedbackText } from '../chunk-7W47WZXY.js';
2
2
  import { ok, core, err } from '@h-ai/core';
3
3
  import { resolveFeedbackBudget, FeedbackSubmitInputSchema, FeedbackBudgetSchema, FeedbackEvidenceInputSchema, FeedbackReportSchema } from '@h-ai/api-contract/feedback';
4
4
 
@@ -45,7 +45,14 @@ async function saveFeedbackFile(bytes, filename, contentType = "application/zip"
45
45
  // src/client/feedback-client-image.ts
46
46
  var PRIVATE_SELECTOR = 'input[type="password"],[data-feedback-private],.rr-block,.rr-mask';
47
47
  var CONTROL_SELECTOR = 'input,textarea,select,[contenteditable]:not([contenteditable="false"])';
48
- async function captureFeedbackScreenshot() {
48
+ async function captureFeedbackScreenshot(signal) {
49
+ signal?.throwIfAborted();
50
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);
51
+ let nodes = 0;
52
+ while (walker.nextNode()) {
53
+ if (++nodes > 1e4)
54
+ throw new RangeError("Screenshot document budget exceeded");
55
+ }
49
56
  if (document.fonts) {
50
57
  let timeout;
51
58
  try {
@@ -55,6 +62,7 @@ async function captureFeedbackScreenshot() {
55
62
  }
56
63
  }
57
64
  const { default: html2canvas } = await import('html2canvas');
65
+ signal?.throwIfAborted();
58
66
  const canvas = await html2canvas(document.body, {
59
67
  width: window.innerWidth,
60
68
  height: window.innerHeight,
@@ -71,6 +79,7 @@ async function captureFeedbackScreenshot() {
71
79
  imageTimeout: 1e3,
72
80
  ignoreElements: (element) => element.matches("[data-feedback-ignore],iframe,video"),
73
81
  onclone: (clone) => {
82
+ signal?.throwIfAborted();
74
83
  const colorCanvas = clone.createElement("canvas");
75
84
  colorCanvas.width = 1;
76
85
  colorCanvas.height = 1;
@@ -124,7 +133,10 @@ async function captureFeedbackScreenshot() {
124
133
  }
125
134
  });
126
135
  try {
127
- return await canvasBytes(canvas);
136
+ signal?.throwIfAborted();
137
+ const bytes = await canvasBytes(canvas);
138
+ signal?.throwIfAborted();
139
+ return bytes;
128
140
  } finally {
129
141
  canvas.width = 0;
130
142
  canvas.height = 0;
@@ -326,7 +338,10 @@ function feedbackFileContentType(file) {
326
338
  ["txt", "text/plain"],
327
339
  ["log", "text/plain"],
328
340
  ["json", "application/json"],
329
- ["pdf", "application/pdf"]
341
+ ["pdf", "application/pdf"],
342
+ ["zip", "application/zip"],
343
+ ["gz", "application/gzip"],
344
+ ["tgz", "application/gzip"]
330
345
  ]);
331
346
  if (!type || type === "application/octet-stream")
332
347
  return extensions.get(file.name.split(".").at(-1)?.toLowerCase() ?? "");
@@ -336,7 +351,9 @@ function feedbackFileContentType(file) {
336
351
  ["image/pjpeg", "image/jpeg"],
337
352
  ["text/json", "application/json"],
338
353
  ["text/x-log", "text/plain"],
339
- ["application/x-pdf", "application/pdf"]
354
+ ["application/x-pdf", "application/pdf"],
355
+ ["application/x-zip-compressed", "application/zip"],
356
+ ["application/x-gzip", "application/gzip"]
340
357
  ]);
341
358
  const normalized = aliases.get(type) ?? type;
342
359
  return [...extensions.values()].includes(normalized) ? normalized : void 0;
@@ -389,6 +406,8 @@ function createFeedbackClient() {
389
406
  let flushTimer;
390
407
  let stopReplay;
391
408
  let screenshotCaptures = 0;
409
+ let captureTask;
410
+ let replayRequested = false;
392
411
  let unsubscribeLogger;
393
412
  let source = "";
394
413
  let keyScreenshots = [];
@@ -407,7 +426,8 @@ function createFeedbackClient() {
407
426
  const key = code === "NOT_INITIALIZED" ? "feedback_notInitialized" : code === "LIMIT_EXCEEDED" ? "feedback_limitExceeded" : code === "INVALID_INPUT" ? "feedback_invalidInput" : "feedback_operationFailed";
408
427
  const traceId = core.context.get().traceId ?? core.context.get().requestId ?? core.id.uuid();
409
428
  const error = { ...HaiFeedbackError[code], traceId, message: message ?? feedbackM(key), cause };
410
- core.logger[cause === void 0 ? "warn" : "error"]("Feedback client operation failed", { module: "feedback", traceId, error });
429
+ if (!(closing && code === "NOT_INITIALIZED"))
430
+ core.logger[cause === void 0 ? "warn" : "error"]("Feedback client operation failed", { module: "feedback", traceId, error });
411
431
  return err({ ...error, message: core.error.formatMessage(error) });
412
432
  }
413
433
  function limits() {
@@ -479,9 +499,9 @@ function createFeedbackClient() {
479
499
  schedulePersist();
480
500
  appendToDraft(item, size);
481
501
  }
482
- function appendToDraft(item, size) {
502
+ function appendToDraft(item, size, snapshot = false) {
483
503
  const bounds = limits();
484
- if (draft && !collectionFinished && !collectionSealed && (Date.now() <= deadline && afterCount < bounds.after || item.kind === "environment") && draft.evidence.length < bounds.events && draftBytes + size <= bounds.bytes) {
504
+ if (draft && !collectionFinished && !collectionSealed && (snapshot || Date.now() <= deadline && afterCount < bounds.after || item.kind === "environment") && draft.evidence.length < bounds.events && draftBytes + size <= bounds.bytes) {
485
505
  draft.evidence.push(item);
486
506
  draftBytes += size;
487
507
  if (item.kind === "log" || item.kind === "error")
@@ -505,6 +525,8 @@ function createFeedbackClient() {
505
525
  const numeric = [input.maxEvents, input.maxBytes, input.maxAgeMs, input.beforeCount, input.afterCount, input.afterTimeoutMs, input.screenshotTimeoutMs, input.maxKeyScreenshots, input.keyScreenshotThrottleMs];
506
526
  if (numeric.some((value) => value !== void 0 && (!Number.isSafeInteger(value) || value < 0)) || input.persistDraft && !input.persistenceKey)
507
527
  return failure("INVALID_INPUT");
528
+ if (input.replayStart !== void 0 && !["init", "prepare"].includes(input.replayStart))
529
+ return failure("INVALID_INPUT");
508
530
  if (!FeedbackSubmitInputSchema.pick({ appId: true, appVersion: true, buildId: true, commit: true }).safeParse({ appId: input.appId, appVersion: input.appVersion, buildId: input.buildId, commit: input.commit }).success)
509
531
  return failure("INVALID_INPUT");
510
532
  const initVersion = sessionVersion;
@@ -592,11 +614,17 @@ function createFeedbackClient() {
592
614
  void saveFeedbackCheckpoint(storageKey, buffer).catch(() => missing.add("browser-persistence-unavailable"));
593
615
  void flush();
594
616
  });
595
- if (input.replay)
617
+ replayRequested = input.replayStart === "init";
618
+ if (input.replay && replayRequested)
596
619
  await startReplay(input);
597
620
  if (closing || config !== input)
598
621
  return failure("NOT_INITIALIZED");
599
622
  flushTimer = setInterval(() => {
623
+ if (draft && Date.now() > deadline && input.replayStart !== "init") {
624
+ replayRequested = false;
625
+ stopReplay?.();
626
+ stopReplay = void 0;
627
+ }
600
628
  if (draft?.report)
601
629
  void flush();
602
630
  }, 1e3);
@@ -611,8 +639,12 @@ function createFeedbackClient() {
611
639
  async function startReplay(activeConfig) {
612
640
  try {
613
641
  const { record: start } = await import('@rrweb/record');
614
- if (closing || config !== activeConfig || screenshotCaptures || stopReplay)
642
+ if (closing || config !== activeConfig || stopReplay)
643
+ return;
644
+ if (screenshotCaptures) {
645
+ missing.add("replay-deferred-by-capture");
615
646
  return;
647
+ }
616
648
  let firstEvent = true;
617
649
  stopReplay = start({
618
650
  maskAllInputs: true,
@@ -638,7 +670,7 @@ function createFeedbackClient() {
638
670
  if (!safe.success)
639
671
  return;
640
672
  replayChunks.at(-1)?.push(safe.data);
641
- appendToDraft(safe.data, new TextEncoder().encode(JSON.stringify(safe.data)).byteLength);
673
+ appendToDraft(safe.data, new TextEncoder().encode(JSON.stringify(safe.data)).byteLength, event.type === 2 || event.type === 4);
642
674
  while (replayChunks.length > 2)
643
675
  replayChunks.shift();
644
676
  const count = replayChunks.reduce((total, chunk) => total + chunk.length, 0);
@@ -655,7 +687,7 @@ function createFeedbackClient() {
655
687
  }
656
688
  }
657
689
  function captureKeyScreenshot() {
658
- if (!config || config.screenshot === false || config.keyScreenshots === false || config.maxKeyScreenshots === 0 || keyScreenshotPromise || Date.now() - lastKeyScreenshot < (config.keyScreenshotThrottleMs ?? 1e4))
690
+ if (!config || config.screenshot === false || config.keyScreenshots !== true || config.maxKeyScreenshots === 0 || keyScreenshotPromise || captureTask || Date.now() - lastKeyScreenshot < (config.keyScreenshotThrottleMs ?? 1e4))
659
691
  return keyScreenshotPromise ?? Promise.resolve();
660
692
  const activeConfig = config;
661
693
  lastKeyScreenshot = Date.now();
@@ -683,19 +715,30 @@ function createFeedbackClient() {
683
715
  return keyScreenshotPromise;
684
716
  }
685
717
  function takeScreenshot(activeConfig) {
718
+ if (captureTask) {
719
+ if (captureTask.config !== activeConfig || captureTask.controller.signal.aborted)
720
+ return Promise.reject(new Error("Screenshot task is still stopping"));
721
+ return bounded(captureTask.promise, activeConfig.screenshotTimeoutMs ?? 3e3, captureTask.controller);
722
+ }
723
+ const controller = new AbortController();
686
724
  screenshotCaptures++;
687
725
  stopReplay?.();
688
726
  stopReplay = void 0;
689
727
  const captured = (async () => {
690
728
  try {
691
- return await (activeConfig.captureScreenshot?.() ?? captureFeedbackScreenshot());
729
+ const bytes = await (activeConfig.captureScreenshot?.({ signal: controller.signal }) ?? captureFeedbackScreenshot(controller.signal));
730
+ controller.signal.throwIfAborted();
731
+ return bytes;
692
732
  } finally {
733
+ await Promise.resolve();
693
734
  screenshotCaptures--;
694
- if (!screenshotCaptures && !closing && config === activeConfig && activeConfig.replay)
695
- await startReplay(activeConfig);
735
+ captureTask = void 0;
736
+ if (!screenshotCaptures && !closing && config?.replay && replayRequested)
737
+ await startReplay(config);
696
738
  }
697
739
  })();
698
- return bounded(captured, activeConfig.screenshotTimeoutMs ?? 3e3);
740
+ captureTask = { promise: captured, controller, config: activeConfig };
741
+ return bounded(captured, activeConfig.screenshotTimeoutMs ?? 3e3, controller);
699
742
  }
700
743
  async function doPrepare() {
701
744
  if (!config || closing)
@@ -717,6 +760,9 @@ function createFeedbackClient() {
717
760
  if (!captured.success)
718
761
  return captured;
719
762
  }
763
+ replayRequested = true;
764
+ if (config.replay && !stopReplay)
765
+ await startReplay(config);
720
766
  return ok(draft);
721
767
  }
722
768
  collectionFinished = false;
@@ -771,6 +817,9 @@ function createFeedbackClient() {
771
817
  draft.missing.push("key-screenshot-budget-exceeded");
772
818
  else draft.attachments.push(image);
773
819
  }
820
+ replayRequested = true;
821
+ if (config.replay && !stopReplay)
822
+ await startReplay(config);
774
823
  schedulePersist();
775
824
  preparedPage = pageIdentity();
776
825
  return ok(draft);
@@ -921,6 +970,8 @@ function createFeedbackClient() {
921
970
  if (!result.success)
922
971
  return result;
923
972
  collectionFinished = true;
973
+ if (config.replayStart !== "init")
974
+ pause();
924
975
  const updatedReport = FeedbackReportSchema.safeParse(result.data);
925
976
  if (updatedReport.success)
926
977
  draft.report = updatedReport.data;
@@ -1050,8 +1101,15 @@ function createFeedbackClient() {
1050
1101
  });
1051
1102
  return closePromise;
1052
1103
  }
1104
+ function pause() {
1105
+ replayRequested = false;
1106
+ stopReplay?.();
1107
+ stopReplay = void 0;
1108
+ captureTask?.controller.abort();
1109
+ }
1053
1110
  async function doClose() {
1054
1111
  closing = true;
1112
+ pause();
1055
1113
  saveController.abort();
1056
1114
  unsubscribeLogger?.();
1057
1115
  unsubscribeLogger = void 0;
@@ -1083,6 +1141,7 @@ function createFeedbackClient() {
1083
1141
  lastError = void 0;
1084
1142
  errorWindows = [];
1085
1143
  replayChunks = [];
1144
+ replayRequested = false;
1086
1145
  keyScreenshots = [];
1087
1146
  lastKeyScreenshot = 0;
1088
1147
  initialIds.clear();
@@ -1092,7 +1151,7 @@ function createFeedbackClient() {
1092
1151
  collectionFinished = false;
1093
1152
  collectionSealed = false;
1094
1153
  }
1095
- return { init, prepare, captureScreenshot, submit, flush, record, getDraft: () => draft, getView, releasePreviews, annotate, addFiles, exportDraft, async saveDraft(input) {
1154
+ return { init, prepare, pause, captureScreenshot, submit, flush, record, getDraft: () => draft, getView, releasePreviews, annotate, addFiles, exportDraft, async saveDraft(input) {
1096
1155
  const session = config;
1097
1156
  const exported = await exportDraft(input);
1098
1157
  if (!exported.success)
@@ -1105,14 +1164,24 @@ function createFeedbackClient() {
1105
1164
  } };
1106
1165
  }
1107
1166
  var feedbackClient = createFeedbackClient();
1108
- async function bounded(promise, ms) {
1167
+ async function bounded(promise, ms, controller) {
1109
1168
  let timer;
1169
+ let aborted;
1110
1170
  try {
1111
1171
  return await Promise.race([promise, new Promise((_resolve, reject) => {
1112
- timer = setTimeout(() => reject(new Error("Capture timed out")), ms);
1172
+ aborted = () => reject(new Error("Capture cancelled"));
1173
+ if (controller.signal.aborted)
1174
+ aborted();
1175
+ else controller.signal.addEventListener("abort", aborted, { once: true });
1176
+ timer = setTimeout(() => {
1177
+ reject(new Error("Capture timed out"));
1178
+ controller.abort();
1179
+ }, ms);
1113
1180
  })]);
1114
1181
  } finally {
1115
1182
  clearTimeout(timer);
1183
+ if (aborted)
1184
+ controller.signal.removeEventListener("abort", aborted);
1116
1185
  }
1117
1186
  }
1118
1187
  async function attachment(name, contentType, bytes) {
@@ -1137,6 +1206,35 @@ function createFeedbackReview(actions) {
1137
1206
  controller.abort();
1138
1207
  controller = new AbortController();
1139
1208
  },
1209
+ async retryReport(id) {
1210
+ const signal = controller.signal;
1211
+ try {
1212
+ const loaded = await actions.get({ id });
1213
+ if (signal.aborted)
1214
+ return failed();
1215
+ if (!loaded.success)
1216
+ return loaded;
1217
+ const targets = /* @__PURE__ */ new Set();
1218
+ if (["partial", "failed"].includes(loaded.data.report.collectionStatus))
1219
+ targets.add("collect");
1220
+ for (const job of loaded.data.jobs) {
1221
+ if (job.status === "failed" && (job.type === "collect" || job.type === "notify" || job.type === "webhook"))
1222
+ targets.add(job.type);
1223
+ }
1224
+ for (const target of targets) {
1225
+ if (signal.aborted)
1226
+ return failed();
1227
+ const retried = await actions.retry({ id, target });
1228
+ if (signal.aborted)
1229
+ return failed();
1230
+ if (!retried.success)
1231
+ return retried;
1232
+ }
1233
+ return ok(void 0);
1234
+ } catch {
1235
+ return failed();
1236
+ }
1237
+ },
1140
1238
  async loadReplay(id) {
1141
1239
  const signal = controller.signal;
1142
1240
  const events = [];