ibc-ai-web-sdk 2.0.4 → 2.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/dist/index.cjs.js CHANGED
@@ -6,7 +6,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
6
6
  * 错误码常量
7
7
  * 统一定义所有错误码,方便维护
8
8
  */
9
-
10
9
  const ERROR_CODES = {
11
10
  // 客户端错误 (40000-49999)
12
11
  AGENT_NOT_FOUND: 40001,
@@ -15,7 +14,6 @@ const ERROR_CODES = {
15
14
  // 提示词不能为空
16
15
  AUTH_FAILED: 40301,
17
16
  // 鉴权失败
18
-
19
17
  // 服务器错误 (50000-59999)
20
18
  NETWORK_ERROR: 500,
21
19
  // 网络请求失败
@@ -23,7 +21,6 @@ const ERROR_CODES = {
23
21
  // 服务器内部错误
24
22
  TIMEOUT_ERROR: 50002,
25
23
  // 请求超时
26
-
27
24
  // 取消
28
25
  REQUEST_CANCELLED: 0 // 请求已取消
29
26
  };
@@ -384,8 +381,25 @@ class AIChatClient {
384
381
  if (conversationId) payload.conversationId = conversationId;
385
382
  const attachmentIds = options.attachmentIds || this.normalizeAttachmentIds(options.attachments);
386
383
  if (attachmentIds.length > 0) payload.attachmentIds = attachmentIds;
387
- const bizParams = options.bizParams || options.extendInfo || this.config.extendInfo;
388
- if (bizParams) payload.bizParams = typeof bizParams === 'string' ? bizParams : JSON.stringify(bizParams);
384
+ let bizParams = options.bizParams || options.extendInfo || this.config.extendInfo;
385
+ if (bizParams) {
386
+ if (typeof bizParams === 'string') {
387
+ try {
388
+ bizParams = JSON.parse(bizParams);
389
+ } catch (e) {
390
+ bizParams = {};
391
+ }
392
+ }
393
+ } else {
394
+ bizParams = {};
395
+ }
396
+ // P3: 将页面上下文合并到 bizParams(contextMode='bizParams' 时由 dialog 传入)
397
+ if (options.context) {
398
+ Object.assign(bizParams, options.context);
399
+ }
400
+ if (Object.keys(bizParams).length > 0) {
401
+ payload.bizParams = JSON.stringify(bizParams);
402
+ }
389
403
  return payload;
390
404
  }
391
405
  normalizeAttachmentIds(attachments) {
@@ -607,14 +621,14 @@ class AIChatClient {
607
621
  const message = parsed && (parsed.message || parsed.errorMessage) || data || '流式请求失败';
608
622
  const code = parsed && (parsed.code || parsed.errCode || parsed.status);
609
623
  if (code && this.isAuthErrorCode(code)) {
610
- const error = new Error(message);
611
- error.authError = true;
612
- error.code = code;
613
- throw error;
624
+ const authErr = new Error(message);
625
+ authErr.authError = true;
626
+ authErr.code = code;
627
+ throw authErr;
614
628
  }
615
- const error = new Error(message);
616
- error.sseData = parsed || data;
617
- throw error;
629
+ const sseErr = new Error(message);
630
+ sseErr.sseData = parsed || data;
631
+ throw sseErr;
618
632
  }
619
633
  if ((META_EVENTS.has(event) || MESSAGE_EVENTS.has(event)) && data.startsWith('[META]')) {
620
634
  const meta = tryParseJson(data.slice('[META]'.length));
@@ -859,7 +873,7 @@ class AIChatClient {
859
873
  }
860
874
 
861
875
  /**
862
- * marked v18.0.5 - a markdown parser
876
+ * marked v18.0.2 - a markdown parser
863
877
  * Copyright (c) 2018-2026, MarkedJS. (MIT License)
864
878
  * Copyright (c) 2011-2018, Christopher Jeffrey. (MIT License)
865
879
  * https://github.com/markedjs/marked
@@ -870,12 +884,12 @@ class AIChatClient {
870
884
  * The code in this file is generated from files in ./src/
871
885
  */
872
886
 
873
- function M(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:null,pedantic:false,renderer:null,silent:false,tokenizer:null,walkTokens:null}}var T=M();function N(l){T=l;}var _={exec:()=>null};function E(l){let e=[];return t=>{let n=Math.max(0,Math.min(3,t-1)),s=e[n];return s||(s=l(n),e[n]=s),s}}function d(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,r)=>{let i=typeof r=="string"?r:r.source;return i=i.replace(m.caret,"$1"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Te=((l="")=>{try{return !!new RegExp("(?<=1)(?<!1)"+l)}catch{return false}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:E(l=>new RegExp(`^ {0,${l}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`)),hrRegex:E(l=>new RegExp(`^ {0,${l}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`)),fencesBeginRegex:E(l=>new RegExp(`^ {0,${l}}(?:\`\`\`|~~~)`)),headingBeginRegex:E(l=>new RegExp(`^ {0,${l}}#`)),htmlBeginRegex:E(l=>new RegExp(`^ {0,${l}}<(?:[a-z].*>|!--)`,"i")),blockquoteBeginRegex:E(l=>new RegExp(`^ {0,${l}}>`))},Oe=/^(?:[ \t]*(?:\n|$))+/,we=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,ye=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,B=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,Pe=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,j=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,oe=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,ae=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Se=d(oe).replace(/bull/g,j).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),F=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,$e=/^[^\n]+/,U=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,Le=d(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",U).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),_e=d(/^(bull)([ \t][^\n]*?)?(?:\n|$)/).replace(/bull/g,j).getRegex(),H="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",K=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,ze=d("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",K).replace("tag",H).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),le=d(F).replace("hr",B).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),Me=d(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",le).getRegex(),W={blockquote:Me,code:we,def:Le,fences:ye,heading:Pe,hr:B,html:ze,lheading:ae,list:_e,newline:Oe,paragraph:le,table:_,text:$e},se=d("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",B).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex(),Ee={...W,lheading:Se,table:se,paragraph:d(F).replace("hr",B).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",se).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]+[^ \\t\\n]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",H).getRegex()},Ie={...W,html:d(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",K).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:_,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:d(F).replace("hr",B).replace("heading",` *#{1,6} *[^
874
- ]`).replace("lheading",ae).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ae=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ce=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,ue=/^( {2,}|\\)\n(?!\s*$)/,Be=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,I=/[\p{P}\p{S}]/u,Z=/[\s\p{P}\p{S}]/u,X=/[^\s\p{P}\p{S}]/u,De=d(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,Z).getRegex(),pe=/(?!~)[\p{P}\p{S}]/u,qe=/(?!~)[\s\p{P}\p{S}]/u,ve=/(?:[^\s\p{P}\p{S}]|~)/u,He=d(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",Te?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),ce=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,Ze=d(ce,"u").replace(/punct/g,I).getRegex(),Ge=d(ce,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Ne=d(he,"gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Qe=d(he,"gu").replace(/notPunctSpace/g,ve).replace(/punctSpace/g,qe).replace(/punct/g,pe).getRegex(),je=d("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),Fe=d(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,I).getRegex(),Ue="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",Ke=d(Ue,"gu").replace(/notPunctSpace/g,X).replace(/punctSpace/g,Z).replace(/punct/g,I).getRegex(),We=d(/\\(punct)/,"gu").replace(/punct/g,I).getRegex(),Xe=d(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Je=d(K).replace("(?:-->|$)","-->").getRegex(),Ve=d("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",Je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),v=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Ye=d(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",v).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=d(/^!?\[(label)\]\[(ref)\]/).replace("label",v).replace("ref",U).getRegex(),de=d(/^!?\[(ref)\](?:\[\])?/).replace("ref",U).getRegex(),et=d("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",de).getRegex(),ie=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,J={_backpedal:_,anyPunctuation:We,autolink:Xe,blockSkip:He,br:ue,code:Ce,del:_,delLDelim:_,delRDelim:_,emStrongLDelim:Ze,emStrongRDelimAst:Ne,emStrongRDelimUnd:je,escape:Ae,link:Ye,nolink:de,punctuation:De,reflink:ke,reflinkSearch:et,tag:Ve,text:Be,url:_},tt={...J,link:d(/^!?\[(label)\]\((.*?)\)/).replace("label",v).getRegex(),reflink:d(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",v).getRegex()},Q={...J,emStrongRDelimAst:Qe,emStrongLDelim:Ge,delLDelim:Fe,delRDelim:Ke,url:d(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",ie).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:d(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",ie).getRegex()},nt={...Q,br:d(ue).replace("{2,}","*").getRegex(),text:d(Q.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},D={normal:W,gfm:Ee,pedantic:Ie},A={normal:J,gfm:Q,breaks:nt,pedantic:tt};var rt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},ge=l=>rt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,ge)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,ge);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,"%");}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=false,a=i;for(;--a>=0&&o[a]==="\\";)u=!u;return u?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function $(l,e,t){let n=l.length;if(n===0)return "";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&true)s++;else break}return l.slice(0,n-s)}function ee(l){let e=l.split(`
887
+ function z(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:null,pedantic:false,renderer:null,silent:false,tokenizer:null,walkTokens:null}}var T=z();function G(l){T=l;}var _={exec:()=>null};function k(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,r)=>{let i=typeof r=="string"?r:r.source;return i=i.replace(m.caret,"$1"),t=t.replace(s,i),n},getRegex:()=>new RegExp(t,e)};return n}var Re=((l="")=>{try{return !!new RegExp("(?<=1)(?<!1)"+l)}catch{return false}})(),m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] +\S/,listReplaceTask:/^\[[ xX]\] +/,listTaskCheckbox:/\[[ xX]\]/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^<a /i,endATag:/^<\/a>/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^</,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}#`),htmlBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}<(?:[a-z].*>|!--)`,"i"),blockquoteBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}>`)},Te=/^(?:[ \t]*(?:\n|$))+/,Oe=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,we=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,I=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ye=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,Q=/ {0,3}(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=k(ie).replace(/bull/g,Q).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Pe=k(ie).replace(/bull/g,Q).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),j=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Se=/^[^\n]+/,F=/(?!\s*\])(?:\\[\s\S]|[^\[\]\\])+/,$e=k(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",F).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Le=k(/^(bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,Q).getRegex(),v="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",U=/<!--(?:-?>|[\s\S]*?(?:-->|$))/,_e=k("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",U).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),ae=k(j).replace("hr",I).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Me=k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",ae).getRegex(),K={blockquote:Me,code:Oe,def:$e,fences:we,heading:ye,hr:I,html:_e,lheading:oe,list:Le,newline:Te,paragraph:ae,table:_,text:Se},re=k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",I).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),ze={...K,lheading:Pe,table:re,paragraph:k(j).replace("hr",I).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)])[ \\t]").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Ee={...K,html:k(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:"[^"]*"|'[^']*'|\\s[^'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",U).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:_,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:k(j).replace("hr",I).replace("heading",` *#{1,6} *[^
888
+ ]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Ae=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,Ce=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,le=/^( {2,}|\\)\n(?!\s*$)/,Ie=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,E=/[\p{P}\p{S}]/u,H=/[\s\p{P}\p{S}]/u,W=/[^\s\p{P}\p{S}]/u,Be=k(/^((?![*_])punctSpace)/,"u").replace(/punctSpace/g,H).getRegex(),ue=/(?!~)[\p{P}\p{S}]/u,De=/(?!~)[\s\p{P}\p{S}]/u,qe=/(?:[^\s\p{P}\p{S}]|~)/u,ve=k(/link|precode-code|html/,"g").replace("link",/\[(?:[^\[\]`]|(?<a>`+)[^`]+\k<a>(?!`))*?\]\((?:\\[\s\S]|[^\\\(\)]|\((?:\\[\s\S]|[^\\\(\)])*\))*\)/).replace("precode-",Re?"(?<!`)()":"(^^|[^`])").replace("code",/(?<b>`+)[^`]+\k<b>(?!`)/).replace("html",/<(?! )[^<>]*?>/).getRegex(),pe=/^(?:\*+(?:((?!\*)punct)|([^\s*]))?)|^_+(?:((?!_)punct)|([^\s_]))?/,He=k(pe,"u").replace(/punct/g,E).getRegex(),Ze=k(pe,"u").replace(/punct/g,ue).getRegex(),ce="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Ge=k(ce,"gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),Ne=k(ce,"gu").replace(/notPunctSpace/g,qe).replace(/punctSpace/g,De).replace(/punct/g,ue).getRegex(),Qe=k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),je=k(/^~~?(?:((?!~)punct)|[^\s~])/,"u").replace(/punct/g,E).getRegex(),Fe="^[^~]+(?=[^~])|(?!~)punct(~~?)(?=[\\s]|$)|notPunctSpace(~~?)(?!~)(?=punctSpace|$)|(?!~)punctSpace(~~?)(?=notPunctSpace)|[\\s](~~?)(?!~)(?=punct)|(?!~)punct(~~?)(?!~)(?=punct)|notPunctSpace(~~?)(?=notPunctSpace)",Ue=k(Fe,"gu").replace(/notPunctSpace/g,W).replace(/punctSpace/g,H).replace(/punct/g,E).getRegex(),Ke=k(/\\(punct)/,"gu").replace(/punct/g,E).getRegex(),We=k(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Xe=k(U).replace("(?:-->|$)","-->").getRegex(),Je=k("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",Xe).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\[\s\S]|[^\[\]\\])*\]|\\[\s\S]|`+(?!`)[^`]*?`+(?!`)|``+(?=\])|[^\[\]\\`])*?/,Ve=k(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]+(?:\n[ \t]*)?|\n[ \t]*)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),he=k(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",F).getRegex(),ke=k(/^!?\[(ref)\](?:\[\])?/).replace("ref",F).getRegex(),Ye=k("reflink|nolink(?!\\()","g").replace("reflink",he).replace("nolink",ke).getRegex(),se=/[hH][tT][tT][pP][sS]?|[fF][tT][pP]/,X={_backpedal:_,anyPunctuation:Ke,autolink:We,blockSkip:ve,br:le,code:Ce,del:_,delLDelim:_,delRDelim:_,emStrongLDelim:He,emStrongRDelimAst:Ge,emStrongRDelimUnd:Qe,escape:Ae,link:Ve,nolink:ke,punctuation:Be,reflink:he,reflinkSearch:Ye,tag:Je,text:Ie,url:_},et={...X,link:k(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:k(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},N={...X,emStrongRDelimAst:Ne,emStrongLDelim:Ze,delLDelim:je,delRDelim:Ue,url:k(/^((?:protocol):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("protocol",se).replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\[\s\S]|[^\\])*?(?:\\[\s\S]|[^\s~\\]))\1(?=[^~]|$)/,text:k(/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|protocol:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/).replace("protocol",se).getRegex()},tt={...N,br:k(le).replace("{2,}","*").getRegex(),text:k(N.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},B={normal:K,gfm:ze,pedantic:Ee},A={normal:X,gfm:N,breaks:tt,pedantic:et};var nt={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},de=l=>nt[l];function O(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,de)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,de);return l}function J(l){try{l=encodeURI(l).replace(m.percentDecode,"%");}catch{return null}return l}function V(l,e){let t=l.replace(m.findPipe,(r,i,o)=>{let u=false,a=i;for(;--a>=0&&o[a]==="\\";)u=!u;return u?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length<e;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(m.slashPipe,"|");return n}function $(l,e,t){let n=l.length;if(n===0)return "";let s=0;for(;s<n;){let r=l.charAt(n-s-1);if(r===e&&true)s++;else break}return l.slice(0,n-s)}function Y(l){let e=l.split(`
875
889
  `),t=e.length-1;for(;t>=0&&m.blankLine.test(e[t]);)t--;return e.length-t<=2?l:e.slice(0,t+1).join(`
876
- `)}function fe(l,e){if(l.indexOf(e[1])===-1)return -1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function me(l,e=0){let t=e,n="";for(let s of l)if(s===" "){let r=4-t%4;n+=" ".repeat(r),t+=r;}else n+=s,t++;return n}function xe(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=true;let u={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=false,u}function st(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
890
+ `)}function ge(l,e){if(l.indexOf(e[1])===-1)return -1;let t=0;for(let n=0;n<l.length;n++)if(l[n]==="\\")n++;else if(l[n]===e[0])t++;else if(l[n]===e[1]&&(t--,t<0))return n;return t>0?-2:-1}function fe(l,e=0){let t=e,n="";for(let s of l)if(s===" "){let r=4-t%4;n+=" ".repeat(r),t+=r;}else n+=s,t++;return n}function me(l,e,t,n,s){let r=e.href,i=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=true;let u={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:r,title:i,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=false,u}function rt(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
877
891
  `).map(r=>{let i=r.match(t.other.beginningSpace);if(i===null)return r;let[o]=i;return o.length>=s.length?r.slice(s.length):r}).join(`
878
- `)}var w=class{options;rules;lexer;constructor(e){this.options=e||T;}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return {type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:ee(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return {type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=st(n,t[3]||"",this.rules);return {type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=$(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim());}return {type:"heading",raw:$(t[0],`
892
+ `)}var w=class{options;rules;lexer;constructor(e){this.options=e||T;}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return {type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=this.options.pedantic?t[0]:Y(t[0]),s=n.replace(this.rules.other.codeRemoveIndent,"");return {type:"code",raw:n,codeBlockStyle:"indented",text:s}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=rt(n,t[3]||"",this.rules);return {type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=$(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim());}return {type:"heading",raw:$(t[0],`
879
893
  `),depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return {type:"hr",raw:$(t[0],`
880
894
  `)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=$(t[0],`
881
895
  `).split(`
@@ -883,24 +897,24 @@ function M(){return {async:false,breaks:false,extensions:null,gfm:true,hooks:nul
883
897
  `),p=c.replace(this.rules.other.blockquoteSetextReplace,`
884
898
  $1`).replace(this.rules.other.blockquoteSetextReplace2,"");s=s?`${s}
885
899
  ${c}`:c,r=r?`${r}
886
- ${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.blockTokens(p,i,true),this.lexer.state.top=k,n.length===0)break;let h=i.at(-1);if(h?.type==="code")break;if(h?.type==="blockquote"){let R=h,f=R.raw+`
900
+ ${p}`:p;let d=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.blockTokens(p,i,true),this.lexer.state.top=d,n.length===0)break;let h=i.at(-1);if(h?.type==="code")break;if(h?.type==="blockquote"){let R=h,f=R.raw+`
887
901
  `+n.join(`
888
902
  `),S=this.blockquote(f);i[i.length-1]=S,s=s.substring(0,s.length-R.raw.length)+S.raw,r=r.substring(0,r.length-R.text.length)+S.text;break}else if(h?.type==="list"){let R=h,f=R.raw+`
889
903
  `+n.join(`
890
904
  `),S=this.list(f);i[i.length-1]=S,s=s.substring(0,s.length-h.raw.length)+S.raw,r=r.substring(0,r.length-R.raw.length)+S.raw,n=f.substring(i.at(-1).raw.length).split(`
891
- `);continue}}return {type:"blockquote",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:false,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let i=this.rules.other.listItemRegex(n),o=false;for(;e;){let a=false,c="",p="";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let k=me(t[2].split(`
905
+ `);continue}}return {type:"blockquote",raw:s,tokens:i,text:r}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim(),s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:false,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let i=this.rules.other.listItemRegex(n),o=false;for(;e;){let a=false,c="",p="";if(!(t=i.exec(e))||this.rules.block.hr.test(e))break;c=t[0],e=e.substring(c.length);let d=fe(t[2].split(`
892
906
  `,1)[0],t[1].length),h=e.split(`
893
- `,1)[0],R=!k.trim(),f=0;if(this.options.pedantic?(f=2,p=k.trimStart()):R?f=t[1].length+1:(f=k.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=k.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`
894
- `,e=e.substring(h.length+1),a=true),!a){let S=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),re=this.rules.other.headingBeginRegex(f),be=this.rules.other.htmlBeginRegex(f),Re=this.rules.other.blockquoteBeginRegex(f);for(;e;){let G=e.split(`
895
- `,1)[0],C;if(h=G,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting," "),C=h):C=h.replace(this.rules.other.tabCharGlobal," "),ne.test(h)||re.test(h)||be.test(h)||Re.test(h)||S.test(h)||te.test(h))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`
896
- `+C.slice(f);else {if(R||k.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||ne.test(k)||re.test(k)||te.test(k))break;p+=`
897
- `+h;}R=!h.trim(),c+=G+`
898
- `,e=e.substring(G.length+1),k=C.slice(f);}}r.loose||(o?r.loose=true:this.rules.other.doubleBlankLine.test(c)&&(o=true)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:false,text:p,tokens:[]}),r.raw+=c;}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){this.lexer.state.top=false,a.tokens=this.lexer.blockTokens(a.text,[]);let c=a.tokens[0];if(a.task&&(c?.type==="text"||c?.type==="paragraph")){a.text=a.text.replace(this.rules.other.listReplaceTask,""),c.raw=c.raw.replace(this.rules.other.listReplaceTask,""),c.text=c.text.replace(this.rules.other.listReplaceTask,"");for(let k=this.lexer.inlineQueue.length-1;k>=0;k--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[k].src)){this.lexer.inlineQueue[k].src=this.lexer.inlineQueue[k].src.replace(this.rules.other.listReplaceTask,"");break}let p=this.rules.other.listTaskCheckbox.exec(a.raw);if(p){let k={type:"checkbox",raw:p[0]+" ",checked:p[0]!=="[ ]"};a.checked=k.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=k.raw+a.tokens[0].raw,a.tokens[0].text=k.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(k)):a.tokens.unshift({type:"paragraph",raw:k.raw,text:k.raw,tokens:[k]}):a.tokens.unshift(k);}}else a.task&&(a.task=false);if(!r.loose){let p=a.tokens.filter(h=>h.type==="space"),k=p.length>0&&p.some(h=>this.rules.other.anyLine.test(h.raw));r.loose=k;}}if(r.loose)for(let a of r.items){a.loose=true;for(let c of a.tokens)c.type==="text"&&(c.type="paragraph");}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=ee(t[0]);return {type:"html",block:true,raw:n,pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return {type:"def",tag:n,raw:$(t[0],`
899
- `),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=Y(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
907
+ `,1)[0],R=!d.trim(),f=0;if(this.options.pedantic?(f=2,p=d.trimStart()):R?f=t[1].length+1:(f=d.search(this.rules.other.nonSpaceChar),f=f>4?1:f,p=d.slice(f),f+=t[1].length),R&&this.rules.other.blankLine.test(h)&&(c+=h+`
908
+ `,e=e.substring(h.length+1),a=true),!a){let S=this.rules.other.nextBulletRegex(f),ee=this.rules.other.hrRegex(f),te=this.rules.other.fencesBeginRegex(f),ne=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f),be=this.rules.other.blockquoteBeginRegex(f);for(;e;){let Z=e.split(`
909
+ `,1)[0],C;if(h=Z,this.options.pedantic?(h=h.replace(this.rules.other.listReplaceNesting," "),C=h):C=h.replace(this.rules.other.tabCharGlobal," "),te.test(h)||ne.test(h)||xe.test(h)||be.test(h)||S.test(h)||ee.test(h))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!h.trim())p+=`
910
+ `+C.slice(f);else {if(R||d.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||te.test(d)||ne.test(d)||ee.test(d))break;p+=`
911
+ `+h;}R=!h.trim(),c+=Z+`
912
+ `,e=e.substring(Z.length+1),d=C.slice(f);}}r.loose||(o?r.loose=true:this.rules.other.doubleBlankLine.test(c)&&(o=true)),r.items.push({type:"list_item",raw:c,task:!!this.options.gfm&&this.rules.other.listIsTask.test(p),loose:false,text:p,tokens:[]}),r.raw+=c;}let u=r.items.at(-1);if(u)u.raw=u.raw.trimEnd(),u.text=u.text.trimEnd();else return;r.raw=r.raw.trimEnd();for(let a of r.items){if(this.lexer.state.top=false,a.tokens=this.lexer.blockTokens(a.text,[]),a.task){if(a.text=a.text.replace(this.rules.other.listReplaceTask,""),a.tokens[0]?.type==="text"||a.tokens[0]?.type==="paragraph"){a.tokens[0].raw=a.tokens[0].raw.replace(this.rules.other.listReplaceTask,""),a.tokens[0].text=a.tokens[0].text.replace(this.rules.other.listReplaceTask,"");for(let p=this.lexer.inlineQueue.length-1;p>=0;p--)if(this.rules.other.listIsTask.test(this.lexer.inlineQueue[p].src)){this.lexer.inlineQueue[p].src=this.lexer.inlineQueue[p].src.replace(this.rules.other.listReplaceTask,"");break}}let c=this.rules.other.listTaskCheckbox.exec(a.raw);if(c){let p={type:"checkbox",raw:c[0]+" ",checked:c[0]!=="[ ]"};a.checked=p.checked,r.loose?a.tokens[0]&&["paragraph","text"].includes(a.tokens[0].type)&&"tokens"in a.tokens[0]&&a.tokens[0].tokens?(a.tokens[0].raw=p.raw+a.tokens[0].raw,a.tokens[0].text=p.raw+a.tokens[0].text,a.tokens[0].tokens.unshift(p)):a.tokens.unshift({type:"paragraph",raw:p.raw,text:p.raw,tokens:[p]}):a.tokens.unshift(p);}}if(!r.loose){let c=a.tokens.filter(d=>d.type==="space"),p=c.length>0&&c.some(d=>this.rules.other.anyLine.test(d.raw));r.loose=p;}}if(r.loose)for(let a of r.items){a.loose=true;for(let c of a.tokens)c.type==="text"&&(c.type="paragraph");}return r}}html(e){let t=this.rules.block.html.exec(e);if(t){let n=Y(t[0]);return {type:"html",block:true,raw:n,pre:t[1]==="pre"||t[1]==="script"||t[1]==="style",text:n}}}def(e){let t=this.rules.block.def.exec(e);if(t){let n=t[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal," "),s=t[2]?t[2].replace(this.rules.other.hrefBrackets,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",r=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return {type:"def",tag:n,raw:$(t[0],`
913
+ `),href:s,title:r}}}table(e){let t=this.rules.block.table.exec(e);if(!t||!this.rules.other.tableDelimiter.test(t[2]))return;let n=V(t[1]),s=t[2].replace(this.rules.other.tableAlignChars,"").split("|"),r=t[3]?.trim()?t[3].replace(this.rules.other.tableRowBlankLine,"").split(`
900
914
  `):[],i={type:"table",raw:$(t[0],`
901
- `),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push("right"):this.rules.other.tableAlignCenter.test(o)?i.align.push("center"):this.rules.other.tableAlignLeft.test(o)?i.align.push("left"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:true,align:i.align[o]});for(let o of r)i.rows.push(Y(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:false,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return {type:"heading",raw:$(t[0],`
915
+ `),header:[],align:[],rows:[]};if(n.length===s.length){for(let o of s)this.rules.other.tableAlignRight.test(o)?i.align.push("right"):this.rules.other.tableAlignCenter.test(o)?i.align.push("center"):this.rules.other.tableAlignLeft.test(o)?i.align.push("left"):i.align.push(null);for(let o=0;o<n.length;o++)i.header.push({text:n[o],tokens:this.lexer.inline(n[o]),header:true,align:i.align[o]});for(let o of r)i.rows.push(V(o,i.header.length).map((u,a)=>({text:u,tokens:this.lexer.inline(u),header:false,align:i.align[a]})));return i}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t){let n=t[1].trim();return {type:"heading",raw:$(t[0],`
902
916
  `),depth:t[2].charAt(0)==="="?1:2,text:n,tokens:this.lexer.inline(n)}}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`
903
- `?t[1].slice(0,-1):t[1];return {type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return {type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return {type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return !this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=true:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=false),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=true:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=false),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:false,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=$(n.slice(0,-1),"\\");if((n.length-i.length)%2===0)return}else {let i=fe(t[2],"()");if(i===-2)return;if(i>-1){let u=(t[0].indexOf("!")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]="";}}let s=t[2],r="";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3]);}else r=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),xe(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return {type:"text",raw:i,text:i}}return xe(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let k=[...s[0]][0].length,h=e.slice(0,i+s.index+k+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return {type:"em",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return {type:"strong",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return {type:"br",raw:t[0]}}del(e,t,n=""){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,k=e.slice(0,i+s.index+p+u),h=k.slice(i,-i);return {type:"del",raw:k,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else {let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(r!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0];}return {type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return {type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:false,inRawBlock:false,top:true};let t={other:m,block:D.normal,inline:A.normal};this.options.pedantic?(t.block=D.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=D.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t;}static get rules(){return {block:D,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
917
+ `?t[1].slice(0,-1):t[1];return {type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return {type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return {type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return !this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=true:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=false),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=true:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=false),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:false,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let i=$(n.slice(0,-1),"\\");if((n.length-i.length)%2===0)return}else {let i=ge(t[2],"()");if(i===-2)return;if(i>-1){let u=(t[0].indexOf("!")===0?5:4)+t[1].length+i;t[2]=t[2].substring(0,i),t[0]=t[0].substring(0,u).trim(),t[3]="";}}let s=t[2],r="";if(this.options.pedantic){let i=this.rules.other.pedanticHrefTitle.exec(s);i&&(s=i[1],r=i[3]);}else r=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),me(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:r&&r.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),r=t[s.toLowerCase()];if(!r){let i=n[0].charAt(0);return {type:"text",raw:i,text:i}}return me(n,r,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||!s[1]&&!s[2]&&!s[3]&&!s[4]||s[4]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[3]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=0,p=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(p.lastIndex=0,t=t.slice(-1*e.length+i);(s=p.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(u=[...o].length,s[3]||s[4]){a+=u;continue}else if((s[5]||s[6])&&i%3&&!((i+u)%3)){c+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a+c);let d=[...s[0]][0].length,h=e.slice(0,i+s.index+d+u);if(Math.min(i,u)%2){let f=h.slice(1,-1);return {type:"em",raw:h,text:f,tokens:this.lexer.inlineTokens(f)}}let R=h.slice(2,-2);return {type:"strong",raw:h,text:R,tokens:this.lexer.inlineTokens(R)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),r=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&r&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return {type:"br",raw:t[0]}}del(e,t,n=""){let s=this.rules.inline.delLDelim.exec(e);if(!s)return;if(!(s[1]||"")||!n||this.rules.inline.punctuation.exec(n)){let i=[...s[0]].length-1,o,u,a=i,c=this.rules.inline.delRDelim;for(c.lastIndex=0,t=t.slice(-1*e.length+i);(s=c.exec(t))!==null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o||(u=[...o].length,u!==i))continue;if(s[3]||s[4]){a+=u;continue}if(a-=u,a>0)continue;u=Math.min(u,u+a);let p=[...s[0]][0].length,d=e.slice(0,i+s.index+p+u),h=d.slice(i,-i);return {type:"del",raw:d,text:h,tokens:this.lexer.inlineTokens(h)}}}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else {let r;do r=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(r!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0];}return {type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return {type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;inlineQueue;tokenizer;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||T,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:false,inRawBlock:false,top:true};let t={other:m,block:B.normal,inline:A.normal};this.options.pedantic?(t.block=B.pedantic,t.inline=A.pedantic):this.options.gfm&&(t.block=B.gfm,this.options.breaks?t.inline=A.breaks:t.inline=A.gfm),this.tokenizer.rules=t;}static get rules(){return {block:B,inline:A}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
904
918
  `),this.blockTokens(e,this.tokens);for(let t=0;t<this.inlineQueue.length;t++){let n=this.inlineQueue[t];this.inlineTokens(n.src,n.tokens);}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[],n=false){this.tokenizer.lexer=this,this.options.pedantic&&(e=e.replace(m.tabCharGlobal," ").replace(m.spaceLine,""));let s=1/0;for(;e;){if(e.length<s)s=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}let r;if(this.options.extensions?.block?.some(o=>(r=o.call({lexer:this},e,t))?(e=e.substring(r.raw.length),t.push(r),true):false))continue;if(r=this.tokenizer.space(e)){e=e.substring(r.raw.length);let o=t.at(-1);r.raw.length===1&&o!==void 0?o.raw+=`
905
919
  `:t.push(r);continue}if(r=this.tokenizer.code(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="paragraph"||o?.type==="text"?(o.raw+=(o.raw.endsWith(`
906
920
  `)?"":`
@@ -914,7 +928,7 @@ ${p}`:p;let k=this.lexer.state.top;if(this.lexer.state.top=true,this.lexer.block
914
928
  `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r),n=i.length!==e.length,e=e.substring(r.raw.length);continue}if(r=this.tokenizer.text(e)){e=e.substring(r.raw.length);let o=t.at(-1);o?.type==="text"?(o.raw+=(o.raw.endsWith(`
915
929
  `)?"":`
916
930
  `)+r.raw,o.text+=`
917
- `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=true,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+"["+"a".repeat(s[0].length-r-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=false,o="",u=1/0;for(;e;){if(e.length<u)u=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}i||(o=""),i=false;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),true):false))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type==="text"&&p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,k=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},k),typeof h=="number"&&h>=0&&(p=Math.min(p,h));}),p<1/0&&p>=0&&(c=e.substring(0,p+1));}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!=="_"&&(o=a.raw.slice(-1)),i=true;let p=t.at(-1);p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t="Infinite loop on byte: "+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T;}space(e){return ""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,"")+`
931
+ `+r.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=o.text):t.push(r);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return this.state.top=true,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){this.tokenizer.lexer=this;let n=e,s=null;if(this.tokens.links){let a=Object.keys(this.tokens.links);if(a.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!==null;)a.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex));}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!==null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);let r;for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!==null;)r=s[2]?s[2].length:0,n=n.slice(0,s.index+r)+"["+"a".repeat(s[0].length-r-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);n=this.options.hooks?.emStrongMask?.call({lexer:this},n)??n;let i=false,o="",u=1/0;for(;e;){if(e.length<u)u=e.length;else {this.infiniteLoopError(e.charCodeAt(0));break}i||(o=""),i=false;let a;if(this.options.extensions?.inline?.some(p=>(a=p.call({lexer:this},e,t))?(e=e.substring(a.raw.length),t.push(a),true):false))continue;if(a=this.tokenizer.escape(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.tag(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.link(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(a.raw.length);let p=t.at(-1);a.type==="text"&&p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(a=this.tokenizer.emStrong(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.codespan(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.br(e)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.del(e,n,o)){e=e.substring(a.raw.length),t.push(a);continue}if(a=this.tokenizer.autolink(e)){e=e.substring(a.raw.length),t.push(a);continue}if(!this.state.inLink&&(a=this.tokenizer.url(e))){e=e.substring(a.raw.length),t.push(a);continue}let c=e;if(this.options.extensions?.startInline){let p=1/0,d=e.slice(1),h;this.options.extensions.startInline.forEach(R=>{h=R.call({lexer:this},d),typeof h=="number"&&h>=0&&(p=Math.min(p,h));}),p<1/0&&p>=0&&(c=e.substring(0,p+1));}if(a=this.tokenizer.inlineText(c)){e=e.substring(a.raw.length),a.raw.slice(-1)!=="_"&&(o=a.raw.slice(-1)),i=true;let p=t.at(-1);p?.type==="text"?(p.raw+=a.raw,p.text+=a.text):t.push(a);continue}if(e){this.infiniteLoopError(e.charCodeAt(0));break}}return t}infiniteLoopError(e){let t="Infinite loop on byte: "+e;if(this.options.silent)console.error(t);else throw new Error(t)}};var y=class{options;parser;constructor(e){this.options=e||T;}space(e){return ""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],r=e.replace(m.endingNewline,"")+`
918
932
  `;return s?'<pre><code class="language-'+O(s)+'">'+(n?r:O(r,true))+`</code></pre>
919
933
  `:"<pre><code>"+(n?r:O(r,true))+`</code></pre>
920
934
  `}blockquote({tokens:e}){return `<blockquote>
@@ -932,68 +946,27 @@ ${this.parser.parse(e)}</blockquote>
932
946
  `}tablerow({text:e}){return `<tr>
933
947
  ${e}</tr>
934
948
  `}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return (e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>
935
- `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=V(e);if(r===null)return s;e=r;let i='<a href="'+e+'"';return t&&(i+=' title="'+O(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=V(e);if(r===null)return O(n);e=r;let i=`<img src="${e}" alt="${O(n)}"`;return t&&(i+=` title="${O(t)}"`),i+=">",i}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var L=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new L;}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(i.type)){t+=o||"";continue}}let r=s;switch(r.type){case "space":{t+=this.renderer.space(r);break}case "hr":{t+=this.renderer.hr(r);break}case "heading":{t+=this.renderer.heading(r);break}case "code":{t+=this.renderer.code(r);break}case "table":{t+=this.renderer.table(r);break}case "blockquote":{t+=this.renderer.blockquote(r);break}case "list":{t+=this.renderer.list(r);break}case "checkbox":{t+=this.renderer.checkbox(r);break}case "html":{t+=this.renderer.html(r);break}case "def":{t+=this.renderer.def(r);break}case "paragraph":{t+=this.renderer.paragraph(r);break}case "text":{t+=this.renderer.text(r);break}default:{let i='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=o||"";continue}}let i=r;switch(i.type){case "escape":{n+=t.text(i);break}case "html":{n+=t.html(i);break}case "link":{n+=t.link(i);break}case "image":{n+=t.image(i);break}case "checkbox":{n+=t.checkbox(i);break}case "strong":{n+=t.strong(i);break}case "em":{n+=t.em(i);break}case "codespan":{n+=t.codespan(i);break}case "br":{n+=t.br(i);break}case "del":{n+=t.del(i);break}case "text":{n+=t.text(i);break}default:{let o='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var q=class{defaults=M();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=L;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case "table":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case "list":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t));}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||false,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===false&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer;}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]));}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens);}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if(["options","parser"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p||""};}s.renderer=r;}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if(["options","rules","lexer"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.tokenizer=r;}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if(["options","block"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return (async()=>{let k=await u.call(r,c);return a.call(r,k)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return (async()=>{let k=await u.apply(r,c);return k===false&&(k=await a.apply(r,c)),k})();let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.hooks=r;}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u};}this.defaults={...this.defaults,...s};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===true&&r.async===false)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return (async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`
936
- Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var z=new q;function g(l,e){return z.parse(l,e)}g.options=g.setOptions=function(l){return z.setOptions(l),g.defaults=z.defaults,N(g.defaults),g};g.getDefaults=M;g.defaults=T;g.use=function(...l){return z.use(...l),g.defaults=z.defaults,N(g.defaults),g};g.walkTokens=function(l,e){return z.walkTokens(l,e)};g.parseInline=z.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=L;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;b.parse;x.lex;
937
-
938
- /*! @license DOMPurify 3.4.8 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.8/LICENSE */
939
-
940
- function _arrayLikeToArray(r, a) {
941
- (null == a || a > r.length) && (a = r.length);
942
- for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
943
- return n;
944
- }
945
- function _arrayWithHoles(r) {
946
- if (Array.isArray(r)) return r;
947
- }
948
- function _iterableToArrayLimit(r, l) {
949
- var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
950
- if (null != t) {
951
- var e,
952
- n,
953
- i,
954
- u,
955
- a = [],
956
- f = true,
957
- o = false;
958
- try {
959
- if (i = (t = t.call(r)).next, 0 === l) ; else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
960
- } catch (r) {
961
- o = true, n = r;
962
- } finally {
963
- try {
964
- if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
965
- } finally {
966
- if (o) throw n;
967
- }
968
- }
969
- return a;
970
- }
971
- }
972
- function _nonIterableRest() {
973
- throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
974
- }
975
- function _slicedToArray(r, e) {
976
- return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();
977
- }
978
- function _unsupportedIterableToArray(r, a) {
979
- if (r) {
980
- if ("string" == typeof r) return _arrayLikeToArray(r, a);
981
- var t = {}.toString.call(r).slice(8, -1);
982
- return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
983
- }
984
- }
985
-
986
- const entries = Object.entries,
987
- setPrototypeOf = Object.setPrototypeOf,
988
- isFrozen = Object.isFrozen,
989
- getPrototypeOf = Object.getPrototypeOf,
990
- getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
991
- let freeze = Object.freeze,
992
- seal = Object.seal,
993
- create = Object.create; // eslint-disable-line import/no-mutable-exports
994
- let _ref = typeof Reflect !== 'undefined' && Reflect,
995
- apply = _ref.apply,
996
- construct = _ref.construct;
949
+ `}strong({tokens:e}){return `<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return `<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return `<code>${O(e,true)}</code>`}br(e){return "<br>"}del({tokens:e}){return `<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),r=J(e);if(r===null)return s;e=r;let i='<a href="'+e+'"';return t&&(i+=' title="'+O(t)+'"'),i+=">"+s+"</a>",i}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let r=J(e);if(r===null)return O(n);e=r;let i=`<img src="${e}" alt="${O(n)}"`;return t&&(i+=` title="${O(t)}"`),i+=">",i}text(e){return "tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:O(e.text)}};var L=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return ""+e}image({text:e}){return ""+e}br(){return ""}checkbox({raw:e}){return e}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||T,this.options.renderer=this.options.renderer||new y,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new L;}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e){this.renderer.parser=this;let t="";for(let n=0;n<e.length;n++){let s=e[n];if(this.options.extensions?.renderers?.[s.type]){let i=s,o=this.options.extensions.renderers[i.type].call({parser:this},i);if(o!==false||!["space","hr","heading","code","table","blockquote","list","html","def","paragraph","text"].includes(i.type)){t+=o||"";continue}}let r=s;switch(r.type){case "space":{t+=this.renderer.space(r);break}case "hr":{t+=this.renderer.hr(r);break}case "heading":{t+=this.renderer.heading(r);break}case "code":{t+=this.renderer.code(r);break}case "table":{t+=this.renderer.table(r);break}case "blockquote":{t+=this.renderer.blockquote(r);break}case "list":{t+=this.renderer.list(r);break}case "checkbox":{t+=this.renderer.checkbox(r);break}case "html":{t+=this.renderer.html(r);break}case "def":{t+=this.renderer.def(r);break}case "paragraph":{t+=this.renderer.paragraph(r);break}case "text":{t+=this.renderer.text(r);break}default:{let i='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(i),"";throw new Error(i)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n="";for(let s=0;s<e.length;s++){let r=e[s];if(this.options.extensions?.renderers?.[r.type]){let o=this.options.extensions.renderers[r.type].call({parser:this},r);if(o!==false||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=o||"";continue}}let i=r;switch(i.type){case "escape":{n+=t.text(i);break}case "html":{n+=t.html(i);break}case "link":{n+=t.link(i);break}case "image":{n+=t.image(i);break}case "checkbox":{n+=t.checkbox(i);break}case "strong":{n+=t.strong(i);break}case "em":{n+=t.em(i);break}case "codespan":{n+=t.codespan(i);break}case "br":{n+=t.br(i);break}case "del":{n+=t.del(i);break}case "text":{n+=t.text(i);break}default:{let o='Token with "'+i.type+'" type was not found.';if(this.options.silent)return console.error(o),"";throw new Error(o)}}}return n}};var P=class{options;block;constructor(e){this.options=e||T;}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens","emStrongMask"]);static passThroughHooksRespectAsync=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?x.lex:x.lexInline}provideParser(e=this.block){return e?b.parse:b.parseInline}};var D=class{defaults=z();options=this.setOptions;parse=this.parseMarkdown(true);parseInline=this.parseMarkdown(false);Parser=b;Renderer=y;TextRenderer=L;Lexer=x;Tokenizer=w;Hooks=P;constructor(...e){this.use(...e);}walkTokens(e,t){let n=[];for(let s of e)switch(n=n.concat(t.call(this,s)),s.type){case "table":{let r=s;for(let i of r.header)n=n.concat(this.walkTokens(i.tokens,t));for(let i of r.rows)for(let o of i)n=n.concat(this.walkTokens(o.tokens,t));break}case "list":{let r=s;n=n.concat(this.walkTokens(r.items,t));break}default:{let r=s;this.defaults.extensions?.childTokens?.[r.type]?this.defaults.extensions.childTokens[r.type].forEach(i=>{let o=r[i].flat(1/0);n=n.concat(this.walkTokens(o,t));}):r.tokens&&(n=n.concat(this.walkTokens(r.tokens,t)));}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||false,n.extensions&&(n.extensions.forEach(r=>{if(!r.name)throw new Error("extension name required");if("renderer"in r){let i=t.renderers[r.name];i?t.renderers[r.name]=function(...o){let u=r.renderer.apply(this,o);return u===false&&(u=i.apply(this,o)),u}:t.renderers[r.name]=r.renderer;}if("tokenizer"in r){if(!r.level||r.level!=="block"&&r.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let i=t[r.level];i?i.unshift(r.tokenizer):t[r.level]=[r.tokenizer],r.start&&(r.level==="block"?t.startBlock?t.startBlock.push(r.start):t.startBlock=[r.start]:r.level==="inline"&&(t.startInline?t.startInline.push(r.start):t.startInline=[r.start]));}"childTokens"in r&&r.childTokens&&(t.childTokens[r.name]=r.childTokens);}),s.extensions=t),n.renderer){let r=this.defaults.renderer||new y(this.defaults);for(let i in n.renderer){if(!(i in r))throw new Error(`renderer '${i}' does not exist`);if(["options","parser"].includes(i))continue;let o=i,u=n.renderer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p||""};}s.renderer=r;}if(n.tokenizer){let r=this.defaults.tokenizer||new w(this.defaults);for(let i in n.tokenizer){if(!(i in r))throw new Error(`tokenizer '${i}' does not exist`);if(["options","rules","lexer"].includes(i))continue;let o=i,u=n.tokenizer[o],a=r[o];r[o]=(...c)=>{let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.tokenizer=r;}if(n.hooks){let r=this.defaults.hooks||new P;for(let i in n.hooks){if(!(i in r))throw new Error(`hook '${i}' does not exist`);if(["options","block"].includes(i))continue;let o=i,u=n.hooks[o],a=r[o];P.passThroughHooks.has(i)?r[o]=c=>{if(this.defaults.async&&P.passThroughHooksRespectAsync.has(i))return (async()=>{let d=await u.call(r,c);return a.call(r,d)})();let p=u.call(r,c);return a.call(r,p)}:r[o]=(...c)=>{if(this.defaults.async)return (async()=>{let d=await u.apply(r,c);return d===false&&(d=await a.apply(r,c)),d})();let p=u.apply(r,c);return p===false&&(p=a.apply(r,c)),p};}s.hooks=r;}if(n.walkTokens){let r=this.defaults.walkTokens,i=n.walkTokens;s.walkTokens=function(o){let u=[];return u.push(i.call(this,o)),r&&(u=u.concat(r.call(this,o))),u};}this.defaults={...this.defaults,...s};}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return (n,s)=>{let r={...s},i={...this.defaults,...r},o=this.onError(!!i.silent,!!i.async);if(this.defaults.async===true&&r.async===false)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return (async()=>{let u=i.hooks?await i.hooks.preprocess(n):n,c=await(i.hooks?await i.hooks.provideLexer(e):e?x.lex:x.lexInline)(u,i),p=i.hooks?await i.hooks.processAllTokens(c):c;i.walkTokens&&await Promise.all(this.walkTokens(p,i.walkTokens));let h=await(i.hooks?await i.hooks.provideParser(e):e?b.parse:b.parseInline)(p,i);return i.hooks?await i.hooks.postprocess(h):h})().catch(o);try{i.hooks&&(n=i.hooks.preprocess(n));let a=(i.hooks?i.hooks.provideLexer(e):e?x.lex:x.lexInline)(n,i);i.hooks&&(a=i.hooks.processAllTokens(a)),i.walkTokens&&this.walkTokens(a,i.walkTokens);let p=(i.hooks?i.hooks.provideParser(e):e?b.parse:b.parseInline)(a,i);return i.hooks&&(p=i.hooks.postprocess(p)),p}catch(u){return o(u)}}}onError(e,t){return n=>{if(n.message+=`
950
+ Please report this to https://github.com/markedjs/marked.`,e){let s="<p>An error occurred:</p><pre>"+O(n.message+"",true)+"</pre>";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new D;function g(l,e){return M.parse(l,e)}g.options=g.setOptions=function(l){return M.setOptions(l),g.defaults=M.defaults,G(g.defaults),g};g.getDefaults=z;g.defaults=T;g.use=function(...l){return M.use(...l),g.defaults=M.defaults,G(g.defaults),g};g.walkTokens=function(l,e){return M.walkTokens(l,e)};g.parseInline=M.parseInline;g.Parser=b;g.parser=b.parse;g.Renderer=y;g.TextRenderer=L;g.Lexer=x;g.lexer=x.lex;g.Tokenizer=w;g.Hooks=P;g.parse=g;g.options;g.setOptions;g.use;g.walkTokens;g.parseInline;b.parse;x.lex;
951
+
952
+ /*! @license DOMPurify 3.4.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.1/LICENSE */
953
+
954
+ const {
955
+ entries,
956
+ setPrototypeOf,
957
+ isFrozen,
958
+ getPrototypeOf,
959
+ getOwnPropertyDescriptor
960
+ } = Object;
961
+ let {
962
+ freeze,
963
+ seal,
964
+ create
965
+ } = Object; // eslint-disable-line import/no-mutable-exports
966
+ let {
967
+ apply,
968
+ construct
969
+ } = typeof Reflect !== 'undefined' && Reflect;
997
970
  if (!freeze) {
998
971
  freeze = function freeze(x) {
999
972
  return x;
@@ -1130,10 +1103,7 @@ function cleanArray(array) {
1130
1103
  */
1131
1104
  function clone(object) {
1132
1105
  const newObject = create(null);
1133
- for (const _ref2 of entries(object)) {
1134
- var _ref3 = _slicedToArray(_ref2, 2);
1135
- const property = _ref3[0];
1136
- const value = _ref3[1];
1106
+ for (const [property, value] of entries(object)) {
1137
1107
  const isPropertyExist = objectHasOwnProperty(object, property);
1138
1108
  if (isPropertyExist) {
1139
1109
  if (arrayIsArray(value)) {
@@ -1247,14 +1217,15 @@ const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mgly
1247
1217
  const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
1248
1218
  const text = freeze(['#text']);
1249
1219
 
1250
- const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
1220
+ const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
1251
1221
  const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
1252
1222
  const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
1253
1223
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
1254
1224
 
1255
- const MUSTACHE_EXPR = seal(/{{[\w\W]*|^[\w\W]*}}/g);
1256
- const ERB_EXPR = seal(/<%[\w\W]*|^[\w\W]*%>/g);
1257
- const TMPLIT_EXPR = seal(/\${[\w\W]*/g);
1225
+ // eslint-disable-next-line unicorn/better-regex
1226
+ const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
1227
+ const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
1228
+ const TMPLIT_EXPR = seal(/\$\{[\w\W]*/gm); // eslint-disable-line unicorn/better-regex
1258
1229
  const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]+$/); // eslint-disable-line no-useless-escape
1259
1230
  const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
1260
1231
  const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
@@ -1265,24 +1236,29 @@ const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205
1265
1236
  const DOCTYPE_NAME = seal(/^html$/i);
1266
1237
  const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
1267
1238
 
1239
+ var EXPRESSIONS = /*#__PURE__*/Object.freeze({
1240
+ __proto__: null,
1241
+ ARIA_ATTR: ARIA_ATTR,
1242
+ ATTR_WHITESPACE: ATTR_WHITESPACE,
1243
+ CUSTOM_ELEMENT: CUSTOM_ELEMENT,
1244
+ DATA_ATTR: DATA_ATTR,
1245
+ DOCTYPE_NAME: DOCTYPE_NAME,
1246
+ ERB_EXPR: ERB_EXPR,
1247
+ IS_ALLOWED_URI: IS_ALLOWED_URI,
1248
+ IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
1249
+ MUSTACHE_EXPR: MUSTACHE_EXPR,
1250
+ TMPLIT_EXPR: TMPLIT_EXPR
1251
+ });
1252
+
1268
1253
  /* eslint-disable @typescript-eslint/indent */
1269
1254
  // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
1270
1255
  const NODE_TYPE = {
1271
1256
  element: 1,
1272
- attribute: 2,
1273
1257
  text: 3,
1274
- cdataSection: 4,
1275
- entityReference: 5,
1276
- // Deprecated
1277
- entityNode: 6,
1278
1258
  // Deprecated
1279
1259
  progressingInstruction: 7,
1280
1260
  comment: 8,
1281
- document: 9,
1282
- documentType: 10,
1283
- documentFragment: 11,
1284
- notation: 12 // Deprecated
1285
- };
1261
+ document: 9};
1286
1262
  const getGlobal = function getGlobal() {
1287
1263
  return typeof window === 'undefined' ? null : window;
1288
1264
  };
@@ -1340,7 +1316,7 @@ const _createHooksMap = function _createHooksMap() {
1340
1316
  function createDOMPurify() {
1341
1317
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
1342
1318
  const DOMPurify = root => createDOMPurify(root);
1343
- DOMPurify.version = '3.4.8';
1319
+ DOMPurify.version = '3.4.1';
1344
1320
  DOMPurify.removed = [];
1345
1321
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
1346
1322
  // Not running in a browser, provide a factory function
@@ -1348,29 +1324,28 @@ function createDOMPurify() {
1348
1324
  DOMPurify.isSupported = false;
1349
1325
  return DOMPurify;
1350
1326
  }
1351
- let document = window.document;
1327
+ let {
1328
+ document
1329
+ } = window;
1352
1330
  const originalDocument = document;
1353
1331
  const currentScript = originalDocument.currentScript;
1354
- window.DocumentFragment;
1355
- const HTMLTemplateElement = window.HTMLTemplateElement,
1356
- Node = window.Node,
1357
- Element = window.Element,
1358
- NodeFilter = window.NodeFilter,
1359
- _window$NamedNodeMap = window.NamedNodeMap;
1360
- _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap;
1361
- window.HTMLFormElement;
1362
- const DOMParser = window.DOMParser,
1363
- trustedTypes = window.trustedTypes;
1332
+ const {
1333
+ DocumentFragment,
1334
+ HTMLTemplateElement,
1335
+ Node,
1336
+ Element,
1337
+ NodeFilter,
1338
+ NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
1339
+ HTMLFormElement,
1340
+ DOMParser,
1341
+ trustedTypes
1342
+ } = window;
1364
1343
  const ElementPrototype = Element.prototype;
1365
1344
  const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
1366
1345
  const remove = lookupGetter(ElementPrototype, 'remove');
1367
1346
  const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
1368
1347
  const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
1369
1348
  const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
1370
- const getShadowRoot = lookupGetter(ElementPrototype, 'shadowRoot');
1371
- const getAttributes = lookupGetter(ElementPrototype, 'attributes');
1372
- const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
1373
- const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
1374
1349
  // As per issue #47, the web-components registry is inherited by a
1375
1350
  // new document created via createHTMLDocument. As per the spec
1376
1351
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
@@ -1385,43 +1360,33 @@ function createDOMPurify() {
1385
1360
  }
1386
1361
  let trustedTypesPolicy;
1387
1362
  let emptyHTML = '';
1388
- // Tracks whether we are already inside a call to the configured Trusted Types
1389
- // policy's `createHTML`. If the supplied `TRUSTED_TYPES_POLICY.createHTML`
1390
- // itself calls `DOMPurify.sanitize` (the cause of #1422), `sanitize` would
1391
- // re-enter the policy and recurse until the stack overflows. We detect that
1392
- // re-entry and throw a clear, actionable error instead.
1393
- let IN_POLICY_CREATE_HTML = 0;
1394
- const _createTrustedHTML = function _createTrustedHTML(html) {
1395
- if (IN_POLICY_CREATE_HTML > 0) {
1396
- throw typeErrorCreate('The configured TRUSTED_TYPES_POLICY.createHTML must not call ' + 'DOMPurify.sanitize, as that causes infinite recursion. Do not pass ' + 'a policy whose createHTML wraps DOMPurify as TRUSTED_TYPES_POLICY; ' + 'see the "DOMPurify and Trusted Types" section of the README.');
1397
- }
1398
- IN_POLICY_CREATE_HTML++;
1399
- try {
1400
- return trustedTypesPolicy.createHTML(html);
1401
- } finally {
1402
- IN_POLICY_CREATE_HTML--;
1403
- }
1404
- };
1405
- const _document = document,
1406
- implementation = _document.implementation,
1407
- createNodeIterator = _document.createNodeIterator,
1408
- createDocumentFragment = _document.createDocumentFragment,
1409
- getElementsByTagName = _document.getElementsByTagName;
1410
- const importNode = originalDocument.importNode;
1363
+ const {
1364
+ implementation,
1365
+ createNodeIterator,
1366
+ createDocumentFragment,
1367
+ getElementsByTagName
1368
+ } = document;
1369
+ const {
1370
+ importNode
1371
+ } = originalDocument;
1411
1372
  let hooks = _createHooksMap();
1412
1373
  /**
1413
1374
  * Expose whether this browser supports running the full DOMPurify.
1414
1375
  */
1415
1376
  DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
1416
- const MUSTACHE_EXPR$1 = MUSTACHE_EXPR,
1417
- ERB_EXPR$1 = ERB_EXPR,
1418
- TMPLIT_EXPR$1 = TMPLIT_EXPR,
1419
- DATA_ATTR$1 = DATA_ATTR,
1420
- ARIA_ATTR$1 = ARIA_ATTR,
1421
- IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA,
1422
- ATTR_WHITESPACE$1 = ATTR_WHITESPACE,
1423
- CUSTOM_ELEMENT$1 = CUSTOM_ELEMENT;
1424
- let IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
1377
+ const {
1378
+ MUSTACHE_EXPR,
1379
+ ERB_EXPR,
1380
+ TMPLIT_EXPR,
1381
+ DATA_ATTR,
1382
+ ARIA_ATTR,
1383
+ IS_SCRIPT_OR_DATA,
1384
+ ATTR_WHITESPACE,
1385
+ CUSTOM_ELEMENT
1386
+ } = EXPRESSIONS;
1387
+ let {
1388
+ IS_ALLOWED_URI: IS_ALLOWED_URI$1
1389
+ } = EXPRESSIONS;
1425
1390
  /**
1426
1391
  * We consider the elements and attributes below to be safe. Ideally
1427
1392
  * don't add any new ones but feel free to remove unwanted ones.
@@ -1729,47 +1694,19 @@ function createDOMPurify() {
1729
1694
  throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
1730
1695
  }
1731
1696
  // Overwrite existing TrustedTypes policy.
1732
- const previousTrustedTypesPolicy = trustedTypesPolicy;
1733
1697
  trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
1734
- // Sign local variables required by `sanitize`. If the supplied policy's
1735
- // `createHTML` is circular (i.e. it calls `DOMPurify.sanitize`), this
1736
- // throws via the re-entrancy guard. Restore the previous policy first so
1737
- // the instance is not left in a poisoned state. See #1422.
1738
- try {
1739
- emptyHTML = _createTrustedHTML('');
1740
- } catch (error) {
1741
- trustedTypesPolicy = previousTrustedTypesPolicy;
1742
- throw error;
1743
- }
1698
+ // Sign local variables required by `sanitize`.
1699
+ emptyHTML = trustedTypesPolicy.createHTML('');
1744
1700
  } else {
1745
1701
  // Uninitialized policy, attempt to initialize the internal dompurify policy.
1746
- if (trustedTypesPolicy === undefined && cfg.TRUSTED_TYPES_POLICY !== null) {
1702
+ if (trustedTypesPolicy === undefined) {
1747
1703
  trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
1748
1704
  }
1749
1705
  // If creating the internal policy succeeded sign internal variables.
1750
- // Note: a falsy `trustedTypesPolicy` (null when policy creation failed or
1751
- // was skipped via `TRUSTED_TYPES_POLICY: null`, or undefined when no
1752
- // policy has been initialized yet) must be excluded here, otherwise we
1753
- // would call `.createHTML` on a non-policy and throw. See #1422.
1754
- if (trustedTypesPolicy && typeof emptyHTML === 'string') {
1755
- emptyHTML = _createTrustedHTML('');
1706
+ if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
1707
+ emptyHTML = trustedTypesPolicy.createHTML('');
1756
1708
  }
1757
1709
  }
1758
- /*
1759
- * Mirror the clone-before-mutate pattern already applied above for
1760
- * cfg.ADD_TAGS / cfg.ADD_ATTR: if any uponSanitize* hook is
1761
- * registered AND the set still points at the default constant,
1762
- * clone it. The hook then mutates the clone (in-call widening
1763
- * still works exactly as documented) and the next default-cfg
1764
- * call rebinds to the untouched original via the reassignment at
1765
- * the top of this function.
1766
- */
1767
- if ((hooks.uponSanitizeElement.length > 0 || hooks.uponSanitizeAttribute.length > 0) && ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
1768
- ALLOWED_TAGS = clone(ALLOWED_TAGS);
1769
- }
1770
- if (hooks.uponSanitizeAttribute.length > 0 && ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
1771
- ALLOWED_ATTR = clone(ALLOWED_ATTR);
1772
- }
1773
1710
  // Prevent further manipulation of configuration.
1774
1711
  // Not available in IE8, Safari 5, etc.
1775
1712
  if (freeze) {
@@ -1929,7 +1866,7 @@ function createDOMPurify() {
1929
1866
  // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
1930
1867
  dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
1931
1868
  }
1932
- const dirtyPayload = trustedTypesPolicy ? _createTrustedHTML(dirty) : dirty;
1869
+ const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
1933
1870
  /*
1934
1871
  * Use the DOMParser API by default, fallback later if needs be
1935
1872
  * DOMParser not work for svg when has multiple root element.
@@ -1969,142 +1906,23 @@ function createDOMPurify() {
1969
1906
  // eslint-disable-next-line no-bitwise
1970
1907
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
1971
1908
  };
1972
- /**
1973
- * Strip template-engine expressions ({{...}}, ${...}, <%...%>) from the
1974
- * character data of an element subtree. Used as the final safety net for
1975
- * SAFE_FOR_TEMPLATES on every DOM-returning code path so that expressions
1976
- * which only form after text-node normalization (e.g. fragments split across
1977
- * stripped elements) cannot survive into a template-evaluating framework.
1978
- *
1979
- * Walks text/comment/CDATA/processing-instruction nodes and mutates `.data`
1980
- * in place rather than round-tripping through innerHTML. This preserves
1981
- * descendant node references (important for IN_PLACE callers), avoids a
1982
- * serialize/reparse cycle, and reads literal character data — which means
1983
- * `<%...%>` in text content matches the ERB regex against its real bytes
1984
- * instead of the HTML-entity-escaped form innerHTML would produce.
1985
- *
1986
- * Attribute values are not visited here; SAFE_FOR_TEMPLATES handling for
1987
- * attributes is performed during the per-node `_sanitizeAttributes` pass.
1988
- *
1989
- * @param node The root element whose character data should be scrubbed.
1990
- */
1991
- const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
1992
- var _node$querySelectorAl, _node$querySelectorAl2;
1993
- node.normalize();
1994
- const walker = createNodeIterator.call(node.ownerDocument || node, node,
1995
- // eslint-disable-next-line no-bitwise
1996
- NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
1997
- let currentNode = walker.nextNode();
1998
- while (currentNode) {
1999
- let data = currentNode.data;
2000
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2001
- data = stringReplace(data, expr, ' ');
2002
- });
2003
- currentNode.data = data;
2004
- currentNode = walker.nextNode();
2005
- }
2006
- // NodeIterator does not descend into <template>.content per the DOM spec,
2007
- // so we must explicitly recurse into each template's content fragment,
2008
- // mirroring the approach used by _sanitizeShadowDOM.
2009
- const templates = (_node$querySelectorAl = (_node$querySelectorAl2 = node.querySelectorAll) === null || _node$querySelectorAl2 === void 0 ? void 0 : _node$querySelectorAl2.call(node, 'template')) !== null && _node$querySelectorAl !== void 0 ? _node$querySelectorAl : [];
2010
- arrayForEach(Array.from(templates), tmpl => {
2011
- if (_isDocumentFragment(tmpl.content)) {
2012
- _scrubTemplateExpressions2(tmpl.content);
2013
- }
2014
- });
2015
- };
2016
1909
  /**
2017
1910
  * _isClobbered
2018
1911
  *
2019
- * Detect DOM-clobbering on HTMLFormElement nodes. Form is the only HTML
2020
- * interface with [LegacyOverrideBuiltIns]; a descendant element with a
2021
- * `name` attribute matching a prototype property shadows that property
2022
- * on direct reads. We use this check at the IN_PLACE entry-point and
2023
- * during attribute sanitization to refuse clobbered forms.
2024
- *
2025
1912
  * @param element element to check for clobbering attacks
2026
1913
  * @return true if clobbered, false if safe
2027
1914
  */
2028
1915
  const _isClobbered = function _isClobbered(element) {
2029
- // Realm-independent tag-name probe. If we can't determine the tag
2030
- // name at all, we can't reason about clobbering — return false
2031
- // (the caller's other defences still apply).
2032
- const realTagName = getNodeName ? getNodeName(element) : null;
2033
- if (typeof realTagName !== 'string') {
2034
- return false;
2035
- }
2036
- if (transformCaseFunc(realTagName) !== 'form') {
2037
- return false;
2038
- }
2039
- return typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' ||
2040
- // Realm-safe NamedNodeMap detection: equality against the cached
2041
- // prototype getter. Clobbered .attributes (e.g. <input name="attributes">)
2042
- // makes the direct read diverge from the cached read; a clean form
2043
- // (same-realm OR foreign-realm) has both reads pointing at the same
2044
- // canonical NamedNodeMap.
2045
- element.attributes !== getAttributes(element) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function' ||
2046
- // NodeType clobbering probe. Cached Node.prototype.nodeType getter
2047
- // returns the integer 1 for any Element regardless of realm; direct
2048
- // read on a clobbered form (e.g. <input name="nodeType">) returns
2049
- // the named child element. Cheap addition — nodeType is read from
2050
- // an internal slot, no serialization cost — and removes a residual
2051
- // clobbering surface used by several mXSS / PI / comment branches
2052
- // in _sanitizeElements that compare currentNode.nodeType directly.
2053
- element.nodeType !== getNodeType(element) ||
2054
- // HTMLFormElement has [LegacyOverrideBuiltIns]: a descendant named
2055
- // "childNodes" shadows the prototype getter. Direct reads of
2056
- // form.childNodes from a clobbered form return the named child
2057
- // instead of the real NodeList, so any walk that reads it directly
2058
- // skips the form's real children. Compare the direct read to the
2059
- // cached Node.prototype getter — when the form's named-property
2060
- // getter intercepts the read, the two values differ and we flag
2061
- // the form. This catches every clobbering child type (input,
2062
- // select, etc.) regardless of whether the named child happens to
2063
- // carry a numeric .length, which a typeof-based probe would miss
2064
- // (e.g. HTMLSelectElement.length is a defined unsigned-long).
2065
- element.childNodes !== getChildNodes(element);
1916
+ return element instanceof HTMLFormElement && (typeof element.nodeName !== 'string' || typeof element.textContent !== 'string' || typeof element.removeChild !== 'function' || !(element.attributes instanceof NamedNodeMap) || typeof element.removeAttribute !== 'function' || typeof element.setAttribute !== 'function' || typeof element.namespaceURI !== 'string' || typeof element.insertBefore !== 'function' || typeof element.hasChildNodes !== 'function');
2066
1917
  };
2067
1918
  /**
2068
- * Checks whether the given value is a DocumentFragment from any realm.
2069
- *
2070
- * The realm-independent replacement reads `nodeType` through the cached
2071
- * Node.prototype getter and compares to the DOCUMENT_FRAGMENT_NODE
2072
- * constant (11). nodeType is a numeric value resolved from the node's
2073
- * internal slot, identical across realms for the same kind of node.
2074
- *
2075
- * @param value object to check
2076
- * @return true if value is a DocumentFragment-shaped node from any realm
2077
- */
2078
- const _isDocumentFragment = function _isDocumentFragment(value) {
2079
- if (!getNodeType || typeof value !== 'object' || value === null) {
2080
- return false;
2081
- }
2082
- try {
2083
- return getNodeType(value) === NODE_TYPE.documentFragment;
2084
- } catch (_) {
2085
- return false;
2086
- }
2087
- };
2088
- /**
2089
- * Checks whether the given object is a DOM node, including nodes that
2090
- * originate from a different window/realm (e.g. an iframe's
2091
- * contentDocument). The previous `value instanceof Node` check was
2092
- * realm-bound: nodes from a different window failed it, causing
2093
- * sanitize() to silently stringify them and reset IN_PLACE to false,
2094
- * returning the original node unsanitized. See GHSA-4w3q-35jp-p934.
1919
+ * Checks whether the given object is a DOM node.
2095
1920
  *
2096
1921
  * @param value object to check whether it's a DOM node
2097
- * @return true if value is a DOM node from any realm
1922
+ * @return true is object is a DOM node
2098
1923
  */
2099
1924
  const _isNode = function _isNode(value) {
2100
- if (!getNodeType || typeof value !== 'object' || value === null) {
2101
- return false;
2102
- }
2103
- try {
2104
- return typeof getNodeType(value) === 'number';
2105
- } catch (_) {
2106
- return false;
2107
- }
1925
+ return typeof Node === 'function' && value instanceof Node;
2108
1926
  };
2109
1927
  function _executeHooks(hooks, currentNode, data) {
2110
1928
  arrayForEach(hooks, hook => {
@@ -2130,7 +1948,7 @@ function createDOMPurify() {
2130
1948
  return true;
2131
1949
  }
2132
1950
  /* Now let's check the element's type and name */
2133
- const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
1951
+ const tagName = transformCaseFunc(currentNode.nodeName);
2134
1952
  /* Execute a hook if present */
2135
1953
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
2136
1954
  tagName,
@@ -2167,17 +1985,10 @@ function createDOMPurify() {
2167
1985
  return false;
2168
1986
  }
2169
1987
  }
2170
- /* Keep content except for bad-listed elements.
2171
- Use the cached prototype getters exclusively — the previous code
2172
- had `|| currentNode.parentNode` / `|| currentNode.childNodes`
2173
- fallbacks, but the cached getters always return the canonical
2174
- value (or null for a real parent-less node), so the fallback
2175
- path was dead in safe cases and a clobbering surface in unsafe
2176
- ones. Falsy cached results stay falsy; the `if (childNodes &&
2177
- parentNode)` check already gates correctly. */
1988
+ /* Keep content except for bad-listed elements */
2178
1989
  if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
2179
- const parentNode = getParentNode(currentNode);
2180
- const childNodes = getChildNodes(currentNode);
1990
+ const parentNode = getParentNode(currentNode) || currentNode.parentNode;
1991
+ const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
2181
1992
  if (childNodes && parentNode) {
2182
1993
  const childCount = childNodes.length;
2183
1994
  for (let i = childCount - 1; i >= 0; --i) {
@@ -2189,14 +2000,8 @@ function createDOMPurify() {
2189
2000
  _forceRemove(currentNode);
2190
2001
  return true;
2191
2002
  }
2192
- /* Check whether element has a valid namespace.
2193
- Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
2194
- nodeType getter rather than `instanceof Element`, which is realm-
2195
- bound and short-circuits to false for any node minted in a different
2196
- realm — letting a foreign-realm element with a forbidden namespace
2197
- slip past the namespace check entirely. */
2198
- const nt = getNodeType ? getNodeType(currentNode) : currentNode.nodeType;
2199
- if (nt === NODE_TYPE.element && !_checkValidNamespace(currentNode)) {
2003
+ /* Check whether element has a valid namespace */
2004
+ if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
2200
2005
  _forceRemove(currentNode);
2201
2006
  return true;
2202
2007
  }
@@ -2209,7 +2014,7 @@ function createDOMPurify() {
2209
2014
  if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
2210
2015
  /* Get the element's text content */
2211
2016
  content = currentNode.textContent;
2212
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2017
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2213
2018
  content = stringReplace(content, expr, ' ');
2214
2019
  });
2215
2020
  if (currentNode.textContent !== content) {
@@ -2241,12 +2046,11 @@ function createDOMPurify() {
2241
2046
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
2242
2047
  return false;
2243
2048
  }
2244
- const nameIsPermitted = ALLOWED_ATTR[lcName] || EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag);
2245
2049
  /* Allow valid data-* attributes: At least one character after "-"
2246
2050
  (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
2247
2051
  XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
2248
2052
  We don't need to check the value; it's always URI safe. */
2249
- if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName)) ; else if (!nameIsPermitted || FORBID_ATTR[lcName]) {
2053
+ if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (EXTRA_ELEMENT_HANDLING.attributeCheck instanceof Function && EXTRA_ELEMENT_HANDLING.attributeCheck(lcName, lcTag)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
2250
2054
  if (
2251
2055
  // First condition does a very basic check if a) it's basically a valid custom element tagname AND
2252
2056
  // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
@@ -2258,7 +2062,7 @@ function createDOMPurify() {
2258
2062
  return false;
2259
2063
  }
2260
2064
  /* Check value is safe. First, is attr inert? If so, is safe */
2261
- } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, ''))) ; else if (value) {
2065
+ } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
2262
2066
  return false;
2263
2067
  } else ;
2264
2068
  return true;
@@ -2276,7 +2080,7 @@ function createDOMPurify() {
2276
2080
  * @returns Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
2277
2081
  */
2278
2082
  const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
2279
- return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT$1, tagName);
2083
+ return !RESERVED_CUSTOM_ELEMENT_NAMES[stringToLowerCase(tagName)] && regExpTest(CUSTOM_ELEMENT, tagName);
2280
2084
  };
2281
2085
  /**
2282
2086
  * _sanitizeAttributes
@@ -2291,7 +2095,9 @@ function createDOMPurify() {
2291
2095
  const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
2292
2096
  /* Execute a hook if present */
2293
2097
  _executeHooks(hooks.beforeSanitizeAttributes, currentNode, null);
2294
- const attributes = currentNode.attributes;
2098
+ const {
2099
+ attributes
2100
+ } = currentNode;
2295
2101
  /* Check if we have attributes; if not we might have a text node */
2296
2102
  if (!attributes || _isClobbered(currentNode)) {
2297
2103
  return;
@@ -2307,9 +2113,11 @@ function createDOMPurify() {
2307
2113
  /* Go backwards over all attributes; safely remove bad ones */
2308
2114
  while (l--) {
2309
2115
  const attr = attributes[l];
2310
- const name = attr.name,
2311
- namespaceURI = attr.namespaceURI,
2312
- attrValue = attr.value;
2116
+ const {
2117
+ name,
2118
+ namespaceURI,
2119
+ value: attrValue
2120
+ } = attr;
2313
2121
  const lcName = transformCaseFunc(name);
2314
2122
  const initValue = attrValue;
2315
2123
  let value = name === 'value' ? initValue : stringTrim(initValue);
@@ -2357,7 +2165,7 @@ function createDOMPurify() {
2357
2165
  }
2358
2166
  /* Sanitize attribute content to be template-safe */
2359
2167
  if (SAFE_FOR_TEMPLATES) {
2360
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2168
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2361
2169
  value = stringReplace(value, expr, ' ');
2362
2170
  });
2363
2171
  }
@@ -2373,7 +2181,7 @@ function createDOMPurify() {
2373
2181
  switch (trustedTypes.getAttributeType(lcTag, lcName)) {
2374
2182
  case 'TrustedHTML':
2375
2183
  {
2376
- value = _createTrustedHTML(value);
2184
+ value = trustedTypesPolicy.createHTML(value);
2377
2185
  break;
2378
2186
  }
2379
2187
  case 'TrustedScriptURL':
@@ -2423,98 +2231,14 @@ function createDOMPurify() {
2423
2231
  _sanitizeElements(shadowNode);
2424
2232
  /* Check attributes next */
2425
2233
  _sanitizeAttributes(shadowNode);
2426
- /* Deep shadow DOM detected.
2427
- Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType against the
2428
- DOCUMENT_FRAGMENT_NODE constant rather than instanceof, so we
2429
- recurse into <template>.content from foreign realms too. */
2430
- if (_isDocumentFragment(shadowNode.content)) {
2234
+ /* Deep shadow DOM detected */
2235
+ if (shadowNode.content instanceof DocumentFragment) {
2431
2236
  _sanitizeShadowDOM2(shadowNode.content);
2432
2237
  }
2433
- /* An element iterated here may itself host an attached
2434
- shadow root. The default NodeIterator does not enter shadow
2435
- trees, so a shadow root nested inside template.content was
2436
- previously reached by no walk at all (the pre-pass at
2437
- _sanitizeAttachedShadowRoots descends via childNodes, which
2438
- doesn't enter template.content; the template-content recursion
2439
- above iterates the content but never inspected shadowRoot).
2440
- Walk it explicitly. The nodeType guard avoids reading
2441
- shadowRoot off text / comment / CDATA / PI nodes that the
2442
- iterator also surfaces. */
2443
- const shadowNodeType = getNodeType ? getNodeType(shadowNode) : shadowNode.nodeType;
2444
- if (shadowNodeType === NODE_TYPE.element) {
2445
- const innerSr = getShadowRoot ? getShadowRoot(shadowNode) : shadowNode.shadowRoot;
2446
- if (_isDocumentFragment(innerSr)) {
2447
- _sanitizeAttachedShadowRoots2(innerSr);
2448
- _sanitizeShadowDOM2(innerSr);
2449
- }
2450
- }
2451
2238
  }
2452
2239
  /* Execute a hook if present */
2453
2240
  _executeHooks(hooks.afterSanitizeShadowDOM, fragment, null);
2454
2241
  };
2455
- /**
2456
- * _sanitizeAttachedShadowRoots
2457
- *
2458
- * Walks `root` and feeds every attached shadow root we encounter into
2459
- * the existing _sanitizeShadowDOM pipeline. The default node iterator
2460
- * does not descend into shadow trees, so nodes inside an attached
2461
- * shadow root would otherwise be skipped entirely.
2462
- *
2463
- * Two real input paths put attached shadow roots in front of us:
2464
- * 1. IN_PLACE on a DOM node that already has shadow roots attached.
2465
- * 2. DOM-node input where importNode(dirty, true) deep-clones the
2466
- * shadow root because it was created with `clonable: true`.
2467
- *
2468
- * This pass runs once, up front, so the main iteration loop (and the
2469
- * existing _sanitizeShadowDOM template-content recursion) stay
2470
- * untouched — string-input paths are not affected.
2471
- *
2472
- * @param root the subtree root to walk for attached shadow roots
2473
- */
2474
- const _sanitizeAttachedShadowRoots2 = function _sanitizeAttachedShadowRoots(root) {
2475
- const nodeType = getNodeType ? getNodeType(root) : root.nodeType;
2476
- if (nodeType === NODE_TYPE.element) {
2477
- const sr = getShadowRoot ? getShadowRoot(root) : root.shadowRoot;
2478
- // Realm-safe check (GHSA-hpcv-96wg-7vj8): use nodeType-based
2479
- // detection rather than `instanceof DocumentFragment`, which is
2480
- // realm-bound and silently skipped shadow roots whose host element
2481
- // belonged to a foreign realm (e.g. iframe.contentDocument
2482
- // attachShadow). A foreign-realm ShadowRoot extends the foreign
2483
- // realm's DocumentFragment, not ours, so the old instanceof check
2484
- // returned false and the shadow subtree was never walked.
2485
- if (_isDocumentFragment(sr)) {
2486
- // Recurse first so that nested shadow roots are reached even if
2487
- // _sanitizeShadowDOM removes hosts at this level.
2488
- _sanitizeAttachedShadowRoots2(sr);
2489
- _sanitizeShadowDOM2(sr);
2490
- }
2491
- }
2492
- // Snapshot children before recursing. Sanitization of one subtree
2493
- // (e.g. via an uponSanitizeShadowNode hook) may detach siblings,
2494
- // and naive nextSibling traversal would silently skip the rest of
2495
- // the list once a node is detached.
2496
- const childNodes = getChildNodes ? getChildNodes(root) : root.childNodes;
2497
- if (!childNodes) {
2498
- return;
2499
- }
2500
- const snapshot = [];
2501
- arrayForEach(childNodes, child => {
2502
- arrayPush(snapshot, child);
2503
- });
2504
- for (const child of snapshot) {
2505
- _sanitizeAttachedShadowRoots2(child);
2506
- }
2507
- /* When the root is a <template>, also descend into root.content */
2508
- if (nodeType === NODE_TYPE.element) {
2509
- const rootName = getNodeName ? getNodeName(root) : null;
2510
- if (typeof rootName === 'string' && transformCaseFunc(rootName) === 'template') {
2511
- const content = root.content;
2512
- if (_isDocumentFragment(content)) {
2513
- _sanitizeAttachedShadowRoots2(content);
2514
- }
2515
- }
2516
- }
2517
- };
2518
2242
  // eslint-disable-next-line complexity
2519
2243
  DOMPurify.sanitize = function (dirty) {
2520
2244
  let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
@@ -2551,35 +2275,15 @@ function createDOMPurify() {
2551
2275
  IN_PLACE = false;
2552
2276
  }
2553
2277
  if (IN_PLACE) {
2554
- /* Do some early pre-sanitization to avoid unsafe root nodes.
2555
- Read nodeName through the cached prototype getter — a clobbering
2556
- child named "nodeName" on the form root would otherwise shadow
2557
- the property and let this check skip the root-allowlist
2558
- validation entirely. */
2559
- const nn = getNodeName ? getNodeName(dirty) : dirty.nodeName;
2278
+ /* Do some early pre-sanitization to avoid unsafe root nodes */
2279
+ const nn = dirty.nodeName;
2560
2280
  if (typeof nn === 'string') {
2561
2281
  const tagName = transformCaseFunc(nn);
2562
2282
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2563
2283
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
2564
2284
  }
2565
2285
  }
2566
- /* Pre-flight the root through _isClobbered. The iterator-driven
2567
- removal path can not detach a parent-less root: _forceRemove
2568
- falls through to Element.prototype.remove(), which per spec
2569
- is a no-op on a node with no parent. A clobbered root would
2570
- then survive the main loop with its attributes uninspected,
2571
- because _sanitizeAttributes early-returns on _isClobbered. The
2572
- result would be an attacker-controlled form, complete with any
2573
- event-handler attributes the caller passed in, handed back to
2574
- the application unsanitized. Refuse to sanitize such a root
2575
- the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
2576
- if (_isClobbered(dirty)) {
2577
- throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
2578
- }
2579
- /* Sanitize attached shadow roots before the main iterator runs.
2580
- The iterator does not descend into shadow trees. */
2581
- _sanitizeAttachedShadowRoots2(dirty);
2582
- } else if (_isNode(dirty)) {
2286
+ } else if (dirty instanceof Node) {
2583
2287
  /* If dirty is a DOM element, append to an empty document to avoid
2584
2288
  elements being stripped by the parser */
2585
2289
  body = _initDocument('<!---->');
@@ -2593,18 +2297,12 @@ function createDOMPurify() {
2593
2297
  // eslint-disable-next-line unicorn/prefer-dom-node-append
2594
2298
  body.appendChild(importedNode);
2595
2299
  }
2596
- /* Clonable shadow roots are deep-cloned by importNode(); sanitize
2597
- them before the main iterator runs, since the iterator does not
2598
- descend into shadow trees. The walk routes every read through a
2599
- cached prototype getter so clobbering descendants on a form root
2600
- cannot hide a shadow host from this pass. */
2601
- _sanitizeAttachedShadowRoots2(importedNode);
2602
2300
  } else {
2603
2301
  /* Exit directly if we have nothing to do */
2604
2302
  if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
2605
2303
  // eslint-disable-next-line unicorn/prefer-includes
2606
2304
  dirty.indexOf('<') === -1) {
2607
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(dirty) : dirty;
2305
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
2608
2306
  }
2609
2307
  /* Initialize the document to work on */
2610
2308
  body = _initDocument(dirty);
@@ -2625,25 +2323,24 @@ function createDOMPurify() {
2625
2323
  _sanitizeElements(currentNode);
2626
2324
  /* Check attributes next */
2627
2325
  _sanitizeAttributes(currentNode);
2628
- /* Shadow DOM detected, sanitize it.
2629
- Realm-safe check (GHSA-hpcv-96wg-7vj8): nodeType-based detection
2630
- instead of instanceof, so foreign-realm <template>.content is
2631
- walked correctly. */
2632
- if (_isDocumentFragment(currentNode.content)) {
2326
+ /* Shadow DOM detected, sanitize it */
2327
+ if (currentNode.content instanceof DocumentFragment) {
2633
2328
  _sanitizeShadowDOM2(currentNode.content);
2634
2329
  }
2635
2330
  }
2636
2331
  /* If we sanitized `dirty` in-place, return it. */
2637
2332
  if (IN_PLACE) {
2638
- if (SAFE_FOR_TEMPLATES) {
2639
- _scrubTemplateExpressions2(dirty);
2640
- }
2641
2333
  return dirty;
2642
2334
  }
2643
2335
  /* Return sanitized string or DOM */
2644
2336
  if (RETURN_DOM) {
2645
2337
  if (SAFE_FOR_TEMPLATES) {
2646
- _scrubTemplateExpressions2(body);
2338
+ body.normalize();
2339
+ let html = body.innerHTML;
2340
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2341
+ html = stringReplace(html, expr, ' ');
2342
+ });
2343
+ body.innerHTML = html;
2647
2344
  }
2648
2345
  if (RETURN_DOM_FRAGMENT) {
2649
2346
  returnNode = createDocumentFragment.call(body.ownerDocument);
@@ -2673,11 +2370,11 @@ function createDOMPurify() {
2673
2370
  }
2674
2371
  /* Sanitize final string template-safe */
2675
2372
  if (SAFE_FOR_TEMPLATES) {
2676
- arrayForEach([MUSTACHE_EXPR$1, ERB_EXPR$1, TMPLIT_EXPR$1], expr => {
2373
+ arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
2677
2374
  serializedHTML = stringReplace(serializedHTML, expr, ' ');
2678
2375
  });
2679
2376
  }
2680
- return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? _createTrustedHTML(serializedHTML) : serializedHTML;
2377
+ return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
2681
2378
  };
2682
2379
  DOMPurify.setConfig = function () {
2683
2380
  let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
@@ -2724,7 +2421,6 @@ var purify = createDOMPurify();
2724
2421
  * 预设主题配置
2725
2422
  * 提供多种常用主题,用户可以直接使用或自定义
2726
2423
  */
2727
-
2728
2424
  /**
2729
2425
  * 默认主题(蓝色渐变)
2730
2426
  */
@@ -2775,7 +2471,6 @@ const DEFAULT_THEME = {
2775
2471
  button: '0 4px 12px rgba(24, 144, 255, 0.35)'
2776
2472
  }
2777
2473
  };
2778
-
2779
2474
  /**
2780
2475
  * 深色主题
2781
2476
  */
@@ -2826,7 +2521,6 @@ const DARK_THEME = {
2826
2521
  button: '0 4px 12px rgba(24, 144, 255, 0.4)'
2827
2522
  }
2828
2523
  };
2829
-
2830
2524
  /**
2831
2525
  * 清新主题(绿色系)
2832
2526
  */
@@ -2877,7 +2571,6 @@ const FRESH_THEME = {
2877
2571
  button: '0 4px 12px rgba(82, 196, 26, 0.35)'
2878
2572
  }
2879
2573
  };
2880
-
2881
2574
  /**
2882
2575
  * 活力主题(橙色系)
2883
2576
  */
@@ -2928,7 +2621,6 @@ const VIBRANT_THEME = {
2928
2621
  button: '0 4px 12px rgba(250, 140, 22, 0.35)'
2929
2622
  }
2930
2623
  };
2931
-
2932
2624
  /**
2933
2625
  * 浪漫主题(粉色系)
2934
2626
  */
@@ -2979,7 +2671,6 @@ const ROMANTIC_THEME = {
2979
2671
  button: '0 4px 12px rgba(235, 47, 150, 0.35)'
2980
2672
  }
2981
2673
  };
2982
-
2983
2674
  /**
2984
2675
  * 紫色主题(优雅神秘)
2985
2676
  */
@@ -3030,7 +2721,6 @@ const PURPLE_THEME = {
3030
2721
  button: '0 4px 12px rgba(114, 46, 209, 0.35)'
3031
2722
  }
3032
2723
  };
3033
-
3034
2724
  /**
3035
2725
  * 海洋主题(深蓝深海)
3036
2726
  */
@@ -3081,7 +2771,6 @@ const OCEAN_THEME = {
3081
2771
  button: '0 4px 12px rgba(0, 119, 182, 0.35)'
3082
2772
  }
3083
2773
  };
3084
-
3085
2774
  /**
3086
2775
  * 暮光主题(紫罗兰渐变)
3087
2776
  */
@@ -3132,7 +2821,6 @@ const TWILIGHT_THEME = {
3132
2821
  button: '0 4px 12px rgba(147, 51, 234, 0.35)'
3133
2822
  }
3134
2823
  };
3135
-
3136
2824
  /**
3137
2825
  * 薄荷主题(青绿色)
3138
2826
  */
@@ -3183,7 +2871,6 @@ const MINT_THEME = {
3183
2871
  button: '0 4px 12px rgba(20, 184, 166, 0.35)'
3184
2872
  }
3185
2873
  };
3186
-
3187
2874
  /**
3188
2875
  * 玫瑰主题(深红色)
3189
2876
  */
@@ -3234,7 +2921,6 @@ const ROSE_THEME = {
3234
2921
  button: '0 4px 12px rgba(225, 29, 72, 0.35)'
3235
2922
  }
3236
2923
  };
3237
-
3238
2924
  /**
3239
2925
  * 极光主题(蓝绿渐变)
3240
2926
  */
@@ -3285,7 +2971,6 @@ const AURORA_THEME = {
3285
2971
  button: '0 4px 12px rgba(14, 165, 233, 0.35)'
3286
2972
  }
3287
2973
  };
3288
-
3289
2974
  /**
3290
2975
  * 薰衣草主题(淡紫色)
3291
2976
  */
@@ -3336,7 +3021,6 @@ const LAVENDER_THEME = {
3336
3021
  button: '0 4px 12px rgba(139, 92, 246, 0.35)'
3337
3022
  }
3338
3023
  };
3339
-
3340
3024
  /**
3341
3025
  * 珊瑚主题(粉橙色)
3342
3026
  */
@@ -3387,7 +3071,6 @@ const CORAL_THEME = {
3387
3071
  button: '0 4px 12px rgba(249, 115, 22, 0.35)'
3388
3072
  }
3389
3073
  };
3390
-
3391
3074
  /**
3392
3075
  * 翡翠主题(深绿色)
3393
3076
  */
@@ -3438,7 +3121,6 @@ const JADE_THEME = {
3438
3121
  button: '0 4px 12px rgba(5, 150, 105, 0.35)'
3439
3122
  }
3440
3123
  };
3441
-
3442
3124
  /**
3443
3125
  * 星空主题(深蓝紫色)
3444
3126
  */
@@ -3489,7 +3171,6 @@ const STARSKY_THEME = {
3489
3171
  button: '0 4px 12px rgba(99, 102, 241, 0.4)'
3490
3172
  }
3491
3173
  };
3492
-
3493
3174
  /**
3494
3175
  * 日落主题(暖色调)
3495
3176
  */
@@ -3540,7 +3221,6 @@ const SUNSET_THEME = {
3540
3221
  button: '0 4px 12px rgba(234, 88, 12, 0.35)'
3541
3222
  }
3542
3223
  };
3543
-
3544
3224
  /**
3545
3225
  * 所有预设主题列表
3546
3226
  */
@@ -3566,27 +3246,21 @@ const PRESET_THEMES = {
3566
3246
  /**
3567
3247
  * AIChatDialog - 纯JavaScript实现的AI对话组件 (Web Components)
3568
3248
  * 样式与功能完全对齐 Vue 版本(1:1 复刻)
3569
- *
3249
+ *
3570
3250
  * @author IBC AI Team
3571
3251
  * @version 2.1.0
3572
3252
  */
3573
-
3574
-
3253
+ // 导入 marked Markdown 解析库 + DOMPurify XSS防护 + 主题配置
3575
3254
  // 运行时占位符(对齐 portal)
3576
3255
  const RUNTIME_PLACEHOLDERS = ['请求已受理', '任务已受理', '正在思考', '正在执行', '结果处理中', '已进入助手运行时', '任务运行时', 'SSE 连接已建立'];
3577
3256
  const DEFAULT_DIALOG_TOP = '96px';
3578
-
3579
3257
  // ========== marked 配置(安全且功能完整) ==========
3258
+ // marked v18 移除了 headerIds/mangle,仅保留 breaks 和 gfm
3580
3259
  g.setOptions({
3581
3260
  breaks: true,
3582
3261
  // 支持GFM换行(单换行变<br>)
3583
- gfm: true,
3584
- // GitHub Flavored Markdown
3585
- headerIds: false,
3586
- // 不生成标题id
3587
- mangle: false // 不转义邮箱
3588
- });
3589
-
3262
+ gfm: true // GitHub Flavored Markdown
3263
+ } /* marked v18 types are strict */);
3590
3264
  // Vue themes.js 的 camelCase key → JS _themeVars CSS变量名 映射表
3591
3265
  const THEME_COLOR_KEY_MAP = {
3592
3266
  primary: '--ai-primary',
@@ -3615,14 +3289,82 @@ const THEME_COLOR_KEY_MAP = {
3615
3289
  error: '--ai-error',
3616
3290
  warning: '--ai-warning'
3617
3291
  };
3618
-
3619
3292
  // ========== 16种预设主题(与Vue版themes.js完全一致) ==========
3620
3293
  class AIChatDialog extends HTMLElement {
3294
+ // ====== 类型声明(HTMLElement 子类必需) ======
3621
3295
  static get observedAttributes() {
3622
3296
  return ['visible'];
3623
3297
  }
3624
3298
  constructor() {
3625
3299
  super();
3300
+ // 核心状态
3301
+ this._messages = [];
3302
+ this._isLoading = false;
3303
+ this._config = null;
3304
+ this._mockMode = false;
3305
+ this._isDragging = false;
3306
+ this._isExpanded = false;
3307
+ this._chatClient = null;
3308
+ this._attachments = [];
3309
+ this._dragStartX = 0;
3310
+ this._dragStartY = 0;
3311
+ this._dialogX = 0;
3312
+ this._dialogY = 0;
3313
+ this._appDetail = null;
3314
+ this._historyVisible = false;
3315
+ this._historyRecords = [];
3316
+ this._historyLoading = false;
3317
+ this._historyLoaded = false;
3318
+ this._historyPageIndex = 1;
3319
+ this._historyHasMore = false;
3320
+ this._isMobile = false;
3321
+ // 流式渲染
3322
+ this._streamTextEl = null;
3323
+ this._streamInitDone = false;
3324
+ this._streamFullText = '';
3325
+ this._streamVisibleLength = 0;
3326
+ this._streamTypeRaf = null;
3327
+ this._streaming = false;
3328
+ // 运行时面板
3329
+ this._runtimePanelEl = null;
3330
+ this._runtimeEventsContainerEl = null;
3331
+ this._runtimeStatusEl = null;
3332
+ this._runtimeCountEl = null;
3333
+ // 页面上下文
3334
+ this._context = {};
3335
+ // 主题
3336
+ this._themeVars = {};
3337
+ // 事件处理器引用(用于清理)
3338
+ this._handleOnline = null;
3339
+ this._handleOffline = null;
3340
+ this._handleResize = null;
3341
+ // DOM 缓存引用
3342
+ this._dialog = null;
3343
+ this._body = null;
3344
+ this._input = null;
3345
+ this._sendBtn = null;
3346
+ this._attachBtn = null;
3347
+ this._attachmentInput = null;
3348
+ this._closeBtn = null;
3349
+ this._expandBtn = null;
3350
+ this._newChatBtn = null;
3351
+ this._historyBtn = null;
3352
+ this._floatBtn = null;
3353
+ this._inputContainer = null;
3354
+ // 会话
3355
+ this._conversationId = null;
3356
+ // 防抖
3357
+ this._lastSendTime = 0;
3358
+ // 拖拽处理器引用
3359
+ this._dragMouseDownHandler = null;
3360
+ this._dragMouseMoveHandler = null;
3361
+ this._dragMouseUpHandler = null;
3362
+ this._dragTouchStartHandler = null;
3363
+ this._dragTouchMoveHandler = null;
3364
+ this._dragTouchEndHandler = null;
3365
+ this._dragInitialized = false;
3366
+ // 错误标记
3367
+ this._ERROR_CONTENT_PATTERNS = ['(请求超时', '(等待AI处理', '(无回复)', '(已停止)', '(AI 处理超时', '错误:', '网络错误:', '抱歉,'];
3626
3368
  this.attachShadow({
3627
3369
  mode: 'open'
3628
3370
  });
@@ -3659,7 +3401,8 @@ class AIChatDialog extends HTMLElement {
3659
3401
  this._runtimeEventsContainerEl = null;
3660
3402
  this._runtimeStatusEl = null;
3661
3403
  this._runtimeCountEl = null;
3662
-
3404
+ // P3: 页面上下文数据(宿主页面选中的数据)
3405
+ this._context = {};
3663
3406
  // ====== 默认主题配置(与 themes.js DEFAULT_THEME 完全一致) ======
3664
3407
  this._themeVars = {
3665
3408
  '--ai-primary': '#1890ff',
@@ -3702,9 +3445,7 @@ class AIChatDialog extends HTMLElement {
3702
3445
  this.render();
3703
3446
  this.bindEvents();
3704
3447
  }
3705
-
3706
3448
  // ==================== 生命周期 ====================
3707
-
3708
3449
  connectedCallback() {
3709
3450
  // P1-8: 网络状态监控(与Vue版一致)
3710
3451
  this._handleOnline = () => {
@@ -3717,12 +3458,11 @@ class AIChatDialog extends HTMLElement {
3717
3458
  tip.className = 'network-tip';
3718
3459
  tip.textContent = '网络连接已断开,请检查网络后重试';
3719
3460
  this._dialog?.prepend(tip);
3720
- setTimeout(() => tip.remove(), 5000);
3461
+ window.setTimeout(() => tip.remove(), 5000);
3721
3462
  }
3722
3463
  };
3723
3464
  window.addEventListener('online', this._handleOnline);
3724
3465
  window.addEventListener('offline', this._handleOffline);
3725
-
3726
3466
  // P2-17: 移动端环境检测(与Vue版 detectEnvironment 一致)
3727
3467
  this._detectMobile();
3728
3468
  // P2-17: 窗口resize时重新检测移动端
@@ -3735,7 +3475,6 @@ class AIChatDialog extends HTMLElement {
3735
3475
  }
3736
3476
  };
3737
3477
  window.addEventListener('resize', this._handleResize);
3738
-
3739
3478
  // 恢复后台Token刷新定时器(SPA路由切换后 re-attach 场景)
3740
3479
  if (this._chatClient) this._chatClient.startBackgroundRefresh();
3741
3480
  }
@@ -3745,13 +3484,14 @@ class AIChatDialog extends HTMLElement {
3745
3484
  if (this._handleOffline) window.removeEventListener('offline', this._handleOffline);
3746
3485
  // P2-17: 清理resize监听
3747
3486
  if (this._handleResize) window.removeEventListener('resize', this._handleResize);
3487
+ // P0: 清理拖拽事件监听
3488
+ this._cleanupDragListeners();
3748
3489
  // 暂停后台Token刷新定时器(detach时停止,re-attach时由connectedCallback恢复)
3749
3490
  if (this._chatClient) {
3750
3491
  this._chatClient.stopBackgroundRefresh();
3751
3492
  this._chatClient.cancelCurrentRequest();
3752
3493
  }
3753
3494
  }
3754
-
3755
3495
  // P2-17: 移动端4维检测(与Vue版 isMobileDevice 计算属性完全一致)
3756
3496
  _detectMobile() {
3757
3497
  // 1. 优先使用显式配置
@@ -3759,31 +3499,25 @@ class AIChatDialog extends HTMLElement {
3759
3499
  this._isMobile = !!this._config.mobileMode;
3760
3500
  return;
3761
3501
  }
3762
-
3763
3502
  // 2. 微信小程序环境检测
3764
3503
  if (typeof wx !== 'undefined' && wx.getSystemInfoSync) {
3765
3504
  this._isMobile = true;
3766
3505
  return;
3767
3506
  }
3768
-
3769
3507
  // 3. 浏览器环境
3770
3508
  if (typeof window === 'undefined') {
3771
3509
  this._isMobile = false;
3772
3510
  return;
3773
3511
  }
3774
-
3775
3512
  // 4. User Agent 正则匹配
3776
3513
  const ua = navigator.userAgent || '';
3777
3514
  const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
3778
-
3779
3515
  // 5. 屏幕宽度 < 768px + 触摸支持
3780
3516
  const isSmallScreen = window.innerWidth < 768;
3781
3517
  const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
3782
-
3783
3518
  // 综合判断:UA匹配 或 (小屏幕+触摸)
3784
3519
  this._isMobile = isMobileUA || isSmallScreen && hasTouch;
3785
3520
  }
3786
-
3787
3521
  // P2-17: 应用移动端/桌面端布局(自动全屏或恢复浮动气泡)
3788
3522
  _applyMobileLayout() {
3789
3523
  if (!this._dialog) return;
@@ -3828,9 +3562,7 @@ class AIChatDialog extends HTMLElement {
3828
3562
  if (visible) this.showDialog();else this.hideDialog();
3829
3563
  }
3830
3564
  }
3831
-
3832
3565
  // ==================== 属性访问器 ====================
3833
-
3834
3566
  get visible() {
3835
3567
  return this.hasAttribute('visible');
3836
3568
  }
@@ -3846,9 +3578,7 @@ class AIChatDialog extends HTMLElement {
3846
3578
  get config() {
3847
3579
  return this._config;
3848
3580
  }
3849
-
3850
3581
  // ==================== 公共API ====================
3851
-
3852
3582
  init(config = {}) {
3853
3583
  this._config = {
3854
3584
  apiBaseUrl: '',
@@ -3896,6 +3626,14 @@ class AIChatDialog extends HTMLElement {
3896
3626
  authFn: null,
3897
3627
  onLoad: null,
3898
3628
  onError: null,
3629
+ // P3: 发送前回调 - 每发消息前调用,可返回最新页面上下文(与 setContext 合并,此回调结果优先)
3630
+ onBeforeSend: null,
3631
+ // P3: 上下文注入方式 — 'prompt'=拼到用户消息前面(默认), 'bizParams'=注入到 bizParams JSON 中
3632
+ contextMode: 'prompt',
3633
+ // P4: 调试模式 - 开启后 console 打印请求/响应/SSE/上下文合并全过程
3634
+ debug: false,
3635
+ // P4: 自定义消息操作按钮 — 返回数组 [{label, className?, onClick}] 在 AI 消息下方渲染
3636
+ onMessageActions: null,
3899
3637
  suggestions: [{
3900
3638
  label: '帮我购买一台轻量应用服务器用于部署应用',
3901
3639
  value: '帮我购买一台轻量应用服务器用于部署应用'
@@ -3909,6 +3647,11 @@ class AIChatDialog extends HTMLElement {
3909
3647
  this._chatClient = new AIChatClient(this._config);
3910
3648
  if (this._conversationId) this._chatClient.setConversationId(this._conversationId);
3911
3649
  this.applyConfig();
3650
+ // P1-2 fix: 在 _config 就绪后初始化拖拽,以正确读取 enableDrag
3651
+ if (this._config?.enableDrag !== false && this.getAttribute('mode') !== 'inline' && !this._dragInitialized) {
3652
+ this.initDraggable();
3653
+ }
3654
+ this._debugLog('初始化完成', 'appId=' + this._config.appId, 'userId=' + this._config.userId, 'baseUrl=' + this._config.apiBaseUrl, 'debug=' + !!this._config.debug, 'contextMode=' + (this._config.contextMode || 'prompt'));
3912
3655
  this.loadAppDetail();
3913
3656
  // 触发 onLoad 回调(与Vue版一致)
3914
3657
  if (this._config?.onLoad) this._config.onLoad(this);
@@ -3994,9 +3737,42 @@ class AIChatDialog extends HTMLElement {
3994
3737
  this._mockMode = false;
3995
3738
  return this;
3996
3739
  }
3997
-
3740
+ /**
3741
+ * 设置页面上下文数据(宿主页面选中的数据,随每次请求发送)
3742
+ * @param {Object} context - 上下文数据对象,传 null 清空
3743
+ * @returns {this}
3744
+ */
3745
+ setContext(context) {
3746
+ this._context = context && typeof context === 'object' ? {
3747
+ ...context
3748
+ } : {};
3749
+ return this;
3750
+ }
3751
+ /**
3752
+ * 获取当前上下文数据
3753
+ * @returns {Object}
3754
+ */
3755
+ getContext() {
3756
+ return {
3757
+ ...this._context
3758
+ };
3759
+ }
3760
+ /**
3761
+ * 外部触发表态发送(业务层主动调用,如点击外部按钮触发 AI 请求)
3762
+ * @param {string} text - 要发送的消息内容
3763
+ * @returns {this}
3764
+ */
3765
+ send(text) {
3766
+ const content = String(text || '').trim();
3767
+ if (!content) return this;
3768
+ if (this._input) this._input.value = content;
3769
+ this._autoResizeInput();
3770
+ this._updateSendButtonState();
3771
+ this._lastSendTime = 0; // 跳过防抖,外部触发视为独立操作
3772
+ this.handleSend();
3773
+ return this;
3774
+ }
3998
3775
  // ==================== 显示/隐藏 ====================
3999
-
4000
3776
  showDialog() {
4001
3777
  const dialog = this.shadowRoot.querySelector('.ai-chat-dialog');
4002
3778
  const btn = this.shadowRoot.querySelector('.float-button');
@@ -4011,9 +3787,7 @@ class AIChatDialog extends HTMLElement {
4011
3787
  if (dialog) dialog.classList.remove('dialog-visible');
4012
3788
  if (btn) btn.style.display = 'flex';
4013
3789
  }
4014
-
4015
3790
  // ==================== 渲染(完整CSS对齐theme.css) ====================
4016
-
4017
3791
  render() {
4018
3792
  const cssVarsStr = Object.entries(this._themeVars).map(([k, v]) => `${k}:${v};`).join('\n ');
4019
3793
  this.shadowRoot.innerHTML = `
@@ -4630,6 +4404,19 @@ class AIChatDialog extends HTMLElement {
4630
4404
  color: var(--ai-success);
4631
4405
  background: rgba(16, 185, 129, 0.08);
4632
4406
  }
4407
+ /* P4: 自定义操作按钮(文本标签型,宽度自适应) */
4408
+ .action-icon.custom-action-btn {
4409
+ width: auto;
4410
+ padding: 4px 10px;
4411
+ font-size: 12px;
4412
+ font-weight: 500;
4413
+ white-space: nowrap;
4414
+ }
4415
+ .action-icon.custom-action-btn:hover {
4416
+ color: #fff;
4417
+ background: var(--ai-primary);
4418
+ transform: translateY(-1px);
4419
+ }
4633
4420
 
4634
4421
  /* ========== 底部输入框(与Vue .dialog-footer 一致) ========== */
4635
4422
  .dialog-footer {
@@ -5091,16 +4878,43 @@ class AIChatDialog extends HTMLElement {
5091
4878
  :host(.dark-theme) blockquote { background: rgba(110, 168, 254, 0.08); }
5092
4879
  :host(.dark-theme) th { background: rgba(110, 168, 254, 0.12); }
5093
4880
  :host(.dark-theme) hr { border-top-color: var(--ai-border); }
4881
+
4882
+ /* ========== 插槽样式(自定义内容区域) ========== */
4883
+ /* header-title 插槽 */
4884
+ ::slotted([slot="header-title"]) {
4885
+ font-size: var(--ai-font-title, 15px);
4886
+ font-weight: 650;
4887
+ color: var(--ai-text);
4888
+ overflow: hidden;
4889
+ text-overflow: ellipsis;
4890
+ white-space: nowrap;
4891
+ }
4892
+ /* input-prepend 插槽 — 输入区上方附加内容 */
4893
+ ::slotted([slot="input-prepend"]) {
4894
+ display: block;
4895
+ padding: 0 4px 8px;
4896
+ }
4897
+ /* footer 插槽 */
4898
+ ::slotted([slot="footer"]) {
4899
+ display: flex;
4900
+ justify-content: space-between;
4901
+ gap: 12px;
4902
+ color: #b5bbc5;
4903
+ font-size: 12px;
4904
+ line-height: 1;
4905
+ }
5094
4906
  </style>
5095
4907
 
5096
4908
  <div class="ai-float-container">
5097
4909
  <!-- 对话框 -->
5098
4910
  <div class="ai-chat-dialog">
5099
- <!-- 头部(含展开/关闭按钮) -->
5100
- <div class="dialog-header">
5101
- <div class="header-left">
5102
- <span class="header-title">${this.escapeHtml(this._config?.title || 'AI 助手')}</span>
5103
- </div>
4911
+ <!-- 头部(含展开/关闭按钮) -->
4912
+ <div class="dialog-header">
4913
+ <div class="header-left">
4914
+ <slot name="header-title">
4915
+ <span class="header-title">${this.escapeHtml(this._config?.title || 'AI 助手')}</span>
4916
+ </slot>
4917
+ </div>
5104
4918
  <div class="header-right">
5105
4919
  <button class="new-chat-btn history-btn" type="button" title="历史记录" aria-label="历史记录">
5106
4920
  <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 4v5h5"/><path d="M12 7v5l3 2"/></svg>
@@ -5124,9 +4938,10 @@ class AIChatDialog extends HTMLElement {
5124
4938
  <!-- 消息区域 -->
5125
4939
  <div class="dialog-body" id="messagesContainer"></div>
5126
4940
 
5127
- <!-- 输入区域 -->
5128
- <div class="dialog-footer">
5129
- <div class="input-container" id="inputContainer">
4941
+ <!-- 输入区域 -->
4942
+ <div class="dialog-footer">
4943
+ <slot name="input-prepend"></slot>
4944
+ <div class="input-container" id="inputContainer">
5130
4945
  <textarea class="message-input" id="msgInput"
5131
4946
  placeholder="请输入您的问题..." autocomplete="off" rows="2"></textarea>
5132
4947
  <div class="input-tools">
@@ -5139,10 +4954,12 @@ class AIChatDialog extends HTMLElement {
5139
4954
  </button>
5140
4955
  </div>
5141
4956
  </div>
5142
- <div class="footer-note">
5143
- <span class="footer-note-left">${this.escapeHtml(this._config?.footerDisclaimer || '')}</span>
5144
- <span class="footer-note-right">${this.escapeHtml(this._config?.footerIdentity || '')}</span>
5145
- </div>
4957
+ <div class="footer-note">
4958
+ <slot name="footer">
4959
+ <span class="footer-note-left">${this.escapeHtml(this._config?.footerDisclaimer || '')}</span>
4960
+ <span class="footer-note-right">${this.escapeHtml(this._config?.footerIdentity || '')}</span>
4961
+ </slot>
4962
+ </div>
5146
4963
  </div>
5147
4964
  </div>
5148
4965
 
@@ -5150,7 +4967,6 @@ class AIChatDialog extends HTMLElement {
5150
4967
  <div class="float-button" id="floatBtn" title="打开AI助手"></div>
5151
4968
  </div>
5152
4969
  `;
5153
-
5154
4970
  // 缓存DOM引用
5155
4971
  this._dialog = this.shadowRoot.querySelector('.ai-chat-dialog');
5156
4972
  this._body = this.shadowRoot.querySelector('#messagesContainer');
@@ -5172,28 +4988,21 @@ class AIChatDialog extends HTMLElement {
5172
4988
  requestAnimationFrame(() => {
5173
4989
  // 关闭按钮
5174
4990
  if (this._closeBtn) this._closeBtn.addEventListener('click', () => this.close());
5175
-
5176
4991
  // 展开/收起按钮
5177
4992
  if (this._expandBtn) this._expandBtn.addEventListener('click', () => this.toggleExpand());
5178
-
5179
4993
  // 新会话按钮
5180
4994
  if (this._newChatBtn) this._newChatBtn.addEventListener('click', () => this.clearChat());
5181
-
5182
4995
  // 历史记录按钮
5183
4996
  if (this._historyBtn) this._historyBtn.addEventListener('click', () => this.toggleHistory());
5184
-
5185
4997
  // 悬浮按钮打开
5186
4998
  if (this._floatBtn) this._floatBtn.addEventListener('click', () => this.open());
5187
-
5188
4999
  // 发送按钮
5189
5000
  if (this._sendBtn) this._sendBtn.addEventListener('click', () => this.handleSend());
5190
-
5191
5001
  // 附件选择
5192
5002
  if (this._attachBtn && this._attachmentInput) {
5193
5003
  this._attachBtn.addEventListener('click', () => this._attachmentInput.click());
5194
5004
  this._attachmentInput.addEventListener('change', () => this._handleAttachmentSelect());
5195
5005
  }
5196
-
5197
5006
  // 输入回车发送
5198
5007
  if (this._input) {
5199
5008
  this._autoResizeInput();
@@ -5209,19 +5018,15 @@ class AIChatDialog extends HTMLElement {
5209
5018
  }
5210
5019
  });
5211
5020
  }
5212
-
5213
- // 拖拽(内嵌模式禁用)
5214
- if (this._dialog && this._config?.enableDrag !== false && this.getAttribute('mode') !== 'inline') this.initDraggable();
5021
+ // 拖拽(内嵌模式禁用)— 由 init() 在 _config 就绪后触发
5022
+ // initDraggable 延迟到 init() 中执行以免 _config 为空
5215
5023
  });
5216
5024
  }
5217
-
5218
5025
  // ==================== 展开/收起 ====================
5219
-
5220
5026
  toggleExpand() {
5221
5027
  this._isExpanded = !this._isExpanded;
5222
5028
  const dlg = this._dialog;
5223
5029
  if (!dlg) return;
5224
-
5225
5030
  // P2-17: 移动端始终全屏,展开/收起无意义(与Vue版 dialogStyle 一致)
5226
5031
  if (this._isMobile) {
5227
5032
  this._isExpanded = false; // 移动端不记录展开状态
@@ -5258,77 +5063,107 @@ class AIChatDialog extends HTMLElement {
5258
5063
  detail: this._isExpanded
5259
5064
  }));
5260
5065
  }
5261
-
5262
5066
  // ==================== 拖拽(与Vue startDrag/onDrag/stopDrag 一致) ====================
5263
-
5264
5067
  initDraggable() {
5265
5068
  const header = this.shadowRoot?.querySelector('.dialog-header');
5266
5069
  if (!header) return;
5070
+ // 清理上一次遗留的 document 级监听(SPA 路由切换场景)
5071
+ this._cleanupDragListeners();
5072
+ const self = this;
5267
5073
  const startDrag = (clientX, clientY) => {
5268
5074
  // P2-17: 移动端禁用拖拽(与Vue版 startTouchDrag: if(isExpanded || isMobile) return 一致)
5269
- if (this._isExpanded || this._isMobile) return;
5270
- this._isDragging = true;
5271
- this._dialog.classList.add('dragging');
5272
- const rect = this._dialog.getBoundingClientRect();
5273
- this._dragStartX = clientX - rect.left;
5274
- this._dragStartY = clientY - rect.top;
5075
+ if (self._isExpanded || self._isMobile) return;
5076
+ self._isDragging = true;
5077
+ self._dialog.classList.add('dragging');
5078
+ const rect = self._dialog.getBoundingClientRect();
5079
+ self._dragStartX = clientX - rect.left;
5080
+ self._dragStartY = clientY - rect.top;
5275
5081
  };
5276
5082
  const onDrag = (clientX, clientY) => {
5277
- if (!this._isDragging) return;
5278
- this._dialogX = clientX - this._dragStartX;
5279
- this._dialogY = clientY - this._dragStartY;
5280
- this._dialog.style.left = this._dialogX + 'px';
5281
- this._dialog.style.right = 'auto';
5282
- this._dialog.style.top = this._dialogY + 'px';
5283
- this._dialog.style.bottom = 'auto';
5083
+ if (!self._isDragging) return;
5084
+ self._dialogX = clientX - self._dragStartX;
5085
+ self._dialogY = clientY - self._dragStartY;
5086
+ self._dialog.style.left = self._dialogX + 'px';
5087
+ self._dialog.style.right = 'auto';
5088
+ self._dialog.style.top = self._dialogY + 'px';
5089
+ self._dialog.style.bottom = 'auto';
5284
5090
  };
5285
5091
  const stopDrag = () => {
5286
- if (this._isDragging) {
5287
- this._isDragging = false;
5288
- this._dialog.classList.remove('dragging');
5092
+ if (self._isDragging) {
5093
+ self._isDragging = false;
5094
+ self._dialog.classList.remove('dragging');
5289
5095
  }
5290
5096
  };
5291
-
5292
- // 鼠标事件(桌面端)
5293
- header.addEventListener('mousedown', e => {
5097
+ // 鼠标事件(桌面端)— 保存引用以便清理
5098
+ this._dragMouseDownHandler = e => {
5294
5099
  if (e.target.closest('button, .header-icon')) return;
5295
5100
  startDrag(e.clientX, e.clientY);
5296
5101
  e.preventDefault();
5297
- });
5298
- document.addEventListener('mousemove', e => {
5102
+ };
5103
+ this._dragMouseMoveHandler = e => {
5299
5104
  onDrag(e.clientX, e.clientY);
5300
- });
5301
- document.addEventListener('mouseup', stopDrag);
5302
-
5105
+ };
5106
+ this._dragMouseUpHandler = stopDrag;
5107
+ header.addEventListener('mousedown', this._dragMouseDownHandler);
5108
+ document.addEventListener('mousemove', this._dragMouseMoveHandler);
5109
+ document.addEventListener('mouseup', this._dragMouseUpHandler);
5303
5110
  // P1-7: 触摸事件(移动端,与Vue版一致)
5304
- header.addEventListener('touchstart', e => {
5305
- if (this._isExpanded) return;
5111
+ this._dragTouchStartHandler = e => {
5112
+ if (self._isExpanded) return;
5306
5113
  if (e.target.closest('button, .header-icon')) return;
5307
5114
  const touch = e.touches[0];
5308
5115
  startDrag(touch.clientX, touch.clientY);
5309
- }, {
5310
- passive: true
5311
- });
5312
- document.addEventListener('touchmove', e => {
5313
- if (!this._isDragging) return;
5116
+ };
5117
+ this._dragTouchMoveHandler = e => {
5118
+ if (!self._isDragging) return;
5314
5119
  const touch = e.touches[0];
5315
5120
  onDrag(touch.clientX, touch.clientY);
5316
- }, {
5121
+ };
5122
+ this._dragTouchEndHandler = stopDrag;
5123
+ header.addEventListener('touchstart', this._dragTouchStartHandler, {
5124
+ passive: true
5125
+ });
5126
+ document.addEventListener('touchmove', this._dragTouchMoveHandler, {
5317
5127
  passive: true
5318
5128
  });
5319
- document.addEventListener('touchend', stopDrag);
5129
+ document.addEventListener('touchend', this._dragTouchEndHandler);
5130
+ this._dragInitialized = true;
5131
+ }
5132
+ // P0: 清理拖拽事件监听(SPA disconnectedCallback / re-init 调用)
5133
+ _cleanupDragListeners() {
5134
+ if (this._dragMouseDownHandler) {
5135
+ const header = this.shadowRoot?.querySelector('.dialog-header');
5136
+ if (header) {
5137
+ header.removeEventListener('mousedown', this._dragMouseDownHandler);
5138
+ header.removeEventListener('touchstart', this._dragTouchStartHandler, {
5139
+ passive: true
5140
+ });
5141
+ }
5142
+ this._dragMouseDownHandler = null;
5143
+ this._dragTouchStartHandler = null;
5144
+ }
5145
+ if (this._dragMouseMoveHandler) {
5146
+ document.removeEventListener('mousemove', this._dragMouseMoveHandler);
5147
+ document.removeEventListener('touchmove', this._dragTouchMoveHandler, {
5148
+ passive: true
5149
+ });
5150
+ document.removeEventListener('mouseup', this._dragMouseUpHandler);
5151
+ document.removeEventListener('touchend', this._dragTouchEndHandler);
5152
+ this._dragMouseMoveHandler = null;
5153
+ this._dragTouchMoveHandler = null;
5154
+ this._dragMouseUpHandler = null;
5155
+ this._dragTouchEndHandler = null;
5156
+ }
5320
5157
  }
5321
5158
  applyConfig() {
5322
5159
  if (!this._config) return;
5323
5160
  // 更新标题
5324
5161
  const titleEl = this.shadowRoot.querySelector('.header-title');
5325
5162
  if (titleEl && this._config.title) titleEl.textContent = this._config.title;
5326
-
5327
5163
  // 更新placeholder
5328
5164
  if (this._input && this._config.placeholder) this._input.placeholder = this._config.placeholder;
5329
5165
  // P1-11: 动态设置输入框最大长度
5330
5166
  if (this._input && this._config.maxLength) this._input.maxLength = this._config.maxLength;
5331
-
5332
5167
  // ====== 主题处理:16种字符串预设 + 对象自定义 ======
5333
5168
  const t = this._config.theme;
5334
5169
  const host = this.shadowRoot.host;
@@ -5357,7 +5192,6 @@ class AIChatDialog extends HTMLElement {
5357
5192
  }
5358
5193
  host.classList.toggle('dark-theme', ['dark', 'starsky'].includes(t.toLowerCase()));
5359
5194
  }
5360
-
5361
5195
  // 对象形式自定义主题 - 也先重置再合并
5362
5196
  if (t && typeof t === 'object') {
5363
5197
  this._resetThemeVars();
@@ -5372,7 +5206,6 @@ class AIChatDialog extends HTMLElement {
5372
5206
  });
5373
5207
  host.classList.remove('dark-theme');
5374
5208
  }
5375
-
5376
5209
  // 应用所有CSS变量到host
5377
5210
  Object.entries(this._themeVars).forEach(([k, v]) => host.style.setProperty(k, v));
5378
5211
  }
@@ -5427,9 +5260,7 @@ class AIChatDialog extends HTMLElement {
5427
5260
  questions
5428
5261
  };
5429
5262
  }
5430
-
5431
5263
  // ==================== 渲染消息(与Vue模板结构一致) ====================
5432
-
5433
5264
  renderMessages(options = {}) {
5434
5265
  if (!this._body) return;
5435
5266
  if (this._historyVisible) {
@@ -5481,23 +5312,22 @@ class AIChatDialog extends HTMLElement {
5481
5312
  <div class="message-content">
5482
5313
  ${hasRuntimeEvents ? this._buildRuntimePanel(msg, idx) : ''}
5483
5314
  ${bubbleContent ? `<div class="${bubbleClass}">${bubbleContent}</div>` : ''}
5484
- ${!msg._isStreaming ? `<div class="message-actions-bar">
5485
- ${msg.type === 'ai' ? `<div class="action-icons">
5486
- <span class="action-icon copy-btn${msg.copied ? ' copied' : ''}" data-idx="${idx}" title="${msg.copied ? '已复制' : '复制'}">${msg.copied ? '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="m20 6-11 11-5-5"/></svg>' : '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'}</span>
5487
- <span class="action-icon regenerate-btn" data-idx="${idx}" title="重新回答"><svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span>
5488
- </div>` : ''}
5315
+ ${!msg._isStreaming ? `<div class="message-actions-bar">
5316
+ ${msg.type === 'ai' ? `<div class="action-icons">
5317
+ <span class="action-icon copy-btn${msg.copied ? ' copied' : ''}" data-idx="${idx}" title="${msg.copied ? '已复制' : '复制'}">${msg.copied ? '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="m20 6-11 11-5-5"/></svg>' : '<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'}</span>
5318
+ <span class="action-icon regenerate-btn" data-idx="${idx}" title="重新回答"><svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M21 12a9 9 0 1 1-2.64-6.36"/><path d="M21 3v6h-6"/></svg></span>
5319
+ ${this._buildCustomActions(msg, idx)}
5320
+ </div>` : ''}
5489
5321
  </div>` : ''}
5490
5322
  </div>
5491
5323
  </div>`;
5492
5324
  });
5493
-
5494
5325
  // 加载状态 — 有执行过程时不展示思考中
5495
5326
  if (this._isLoading && !runtimeExists) {
5496
5327
  html += '<div class="message-item ai">' + '<div class="message-content">' + '<div class="message-bubble loading"><span class="thinking-text">思考中</span><span class="typing-indicator"><span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span></span></div>' + '</div>' + '</div>';
5497
5328
  }
5498
5329
  html += '</div>';
5499
5330
  this._body.innerHTML = html;
5500
-
5501
5331
  // 绑定复制事件
5502
5332
  this._body.querySelectorAll('.copy-btn').forEach(btn => {
5503
5333
  btn.addEventListener('click', () => {
@@ -5506,7 +5336,6 @@ class AIChatDialog extends HTMLElement {
5506
5336
  if (msg) this.copyMessage(msg.content, idx);
5507
5337
  });
5508
5338
  });
5509
-
5510
5339
  // 绑定重新生成事件
5511
5340
  this._body.querySelectorAll('.regenerate-btn').forEach(btn => {
5512
5341
  btn.addEventListener('click', () => {
@@ -5514,7 +5343,23 @@ class AIChatDialog extends HTMLElement {
5514
5343
  this.regenerate(idx);
5515
5344
  });
5516
5345
  });
5517
-
5346
+ // P4: 绑定自定义操作按钮
5347
+ this._body.querySelectorAll('.custom-action-btn').forEach(btn => {
5348
+ btn.addEventListener('click', () => {
5349
+ const idx = parseInt(btn.dataset.idx);
5350
+ const actionIdx = parseInt(btn.dataset.action);
5351
+ const msg = this._messages[idx];
5352
+ if (!msg) return;
5353
+ try {
5354
+ const actions = this._getCustomActions(msg, idx);
5355
+ if (actions && actions[actionIdx]) {
5356
+ actions[actionIdx].onClick(msg.content);
5357
+ }
5358
+ } catch (e) {
5359
+ console.warn('[AIChatDialog] 自定义操作按钮执行失败:', e);
5360
+ }
5361
+ });
5362
+ });
5518
5363
  // 绑定执行过程面板折叠/展开(Shadow DOM 下 inline onclick 不可靠)
5519
5364
  this._body.querySelectorAll('.runtime-header').forEach(header => {
5520
5365
  header.addEventListener('click', () => {
@@ -5757,9 +5602,7 @@ class AIChatDialog extends HTMLElement {
5757
5602
  }
5758
5603
  this._updateSendButtonState();
5759
5604
  }
5760
-
5761
5605
  // ==================== 发送消息(与Vue sendMessage 一致) ====================
5762
-
5763
5606
  async handleSend() {
5764
5607
  const content = this._input ? this._input.value.trim() : '';
5765
5608
  const attachments = [...(this._attachments || [])];
@@ -5767,15 +5610,13 @@ class AIChatDialog extends HTMLElement {
5767
5610
  this.showToast(this._config?.emptyMessageError || '请输入消息内容');
5768
5611
  return;
5769
5612
  }
5770
- if (this._isLoading) return;
5771
-
5613
+ if (this._isLoading || this._streaming) return;
5772
5614
  // P1-11: 字数限制检查
5773
5615
  const maxLen = this._config?.maxLength ?? 500;
5774
5616
  if (content.length > maxLen) {
5775
5617
  this.showToast(`输入内容不能超过${maxLen}个字符(当前${content.length}字)`);
5776
5618
  return;
5777
5619
  }
5778
-
5779
5620
  // 防抖:500ms内不允许重复发送
5780
5621
  const now = Date.now();
5781
5622
  if (this._lastSendTime && now - this._lastSendTime < 500) return;
@@ -5823,8 +5664,46 @@ class AIChatDialog extends HTMLElement {
5823
5664
  attachmentIds.push(res.data.attachmentId);
5824
5665
  }
5825
5666
  }
5826
- await this.sendMessageToAI(content || attachmentText, {
5827
- attachmentIds
5667
+ // P3: 收集页面上下文(setContext + onBeforeSend)
5668
+ let context = {
5669
+ ...(this._context || {})
5670
+ };
5671
+ if (typeof this._config?.onBeforeSend === 'function') {
5672
+ try {
5673
+ const dynamicCtx = await this._config.onBeforeSend();
5674
+ if (dynamicCtx && typeof dynamicCtx === 'object') {
5675
+ context = {
5676
+ ...context,
5677
+ ...dynamicCtx
5678
+ };
5679
+ }
5680
+ } catch (e) {
5681
+ console.warn('[AIChatDialog] onBeforeSend 执行失败:', e);
5682
+ }
5683
+ }
5684
+ const hasContext = context && Object.keys(context).length > 0;
5685
+ const rawMode = this._config?.contextMode;
5686
+ const VALID_CONTEXT_MODES = ['prompt', 'bizParams'];
5687
+ const contextMode = VALID_CONTEXT_MODES.includes(rawMode) ? rawMode : rawMode ? (console.warn('[AIChatDialog] 无效的 contextMode: "' + rawMode + '",已回退为 "prompt"(有效值: ' + VALID_CONTEXT_MODES.join(', ') + ')'), 'prompt') : 'prompt';
5688
+ let finalPrompt = content || attachmentText;
5689
+ let contextForBizParams = null;
5690
+ if (hasContext) {
5691
+ this._debugLog('上下文合并', 'keys=', Object.keys(context), 'mode=', contextMode);
5692
+ if (contextMode === 'bizParams') {
5693
+ // 注入到 bizParams
5694
+ contextForBizParams = context;
5695
+ } else {
5696
+ // 默认:拼到 prompt 前面
5697
+ const ctxText = this._formatContextText(context);
5698
+ if (ctxText) {
5699
+ finalPrompt = ctxText + '\n---\n' + finalPrompt;
5700
+ }
5701
+ }
5702
+ }
5703
+ this._debugLog('发送', 'prompt=' + (finalPrompt || '').substring(0, 150) + (finalPrompt && finalPrompt.length > 150 ? '...' : ''), 'ctxKeys=' + Object.keys(contextForBizParams || context || {}).join(','), 'mode=' + contextMode);
5704
+ await this.sendMessageToAI(finalPrompt, {
5705
+ attachmentIds,
5706
+ context: contextForBizParams
5828
5707
  });
5829
5708
  } catch (err) {
5830
5709
  console.error('[AIChatDialog] Error:', err);
@@ -5858,14 +5737,14 @@ class AIChatDialog extends HTMLElement {
5858
5737
  ...(options.streamOptions || {})
5859
5738
  };
5860
5739
  if (options.attachmentIds?.length) streamOpts.attachmentIds = options.attachmentIds;
5740
+ if (options.context) streamOpts.context = options.context;
5861
5741
  await this._directApiCallStream(msgId, content, streamOpts);
5862
5742
  }
5863
5743
  }
5864
5744
  async mockResponse(userContent) {
5865
- await new Promise(r => setTimeout(r, 600 + Math.random() * 800));
5745
+ await new Promise(r => window.setTimeout(r, 600 + Math.random() * 800));
5866
5746
  const responses = [`关于"${(userContent || '').substring(0, 20)}"这个问题,我来为您详细解答...`, `这是一个很好的问题!根据我的理解:\n\n1. 首先,我们需要分析需求\n2. 其次,设计实现方案\n3. 最后,进行测试验证`, `收到您的问题。让我来帮您分析一下...\n\n根据您的描述,我建议您可以按照以下步骤操作:`, `感谢您的提问!以下是我的看法:\n\n• 第一点很关键,需要注意细节\n• 第二点值得关注\n• 第三点是核心所在`];
5867
5747
  const mockContent = responses[Math.floor(Math.random() * responses.length)];
5868
-
5869
5748
  // 流式效果
5870
5749
  const tempId = this.generateId();
5871
5750
  this._messages.push({
@@ -5876,7 +5755,7 @@ class AIChatDialog extends HTMLElement {
5876
5755
  });
5877
5756
  this.renderMessages();
5878
5757
  for (let i = 0; i < mockContent.length; i++) {
5879
- await new Promise(r => setTimeout(r, 12 + Math.random() * 20));
5758
+ await new Promise(r => window.setTimeout(r, 12 + Math.random() * 20));
5880
5759
  const msgIdx = this._messages.findIndex(m => m.id === tempId);
5881
5760
  if (msgIdx >= 0) {
5882
5761
  this._messages[msgIdx].content = mockContent.substring(0, i + 1);
@@ -5908,13 +5787,15 @@ class AIChatDialog extends HTMLElement {
5908
5787
  if (idx >= 0) delete this._messages[idx]._isStreaming;
5909
5788
  this.renderMessages();
5910
5789
  }
5911
-
5912
5790
  // P0: 会话ID管理
5913
- _conversationId = null;
5914
5791
  async _directApiCallStream(msgId, content, requestOptions = {}) {
5915
5792
  if (!this._chatClient) {
5916
5793
  this._chatClient = new AIChatClient(this._config || {});
5917
5794
  }
5795
+ if (this._config?.debug) {
5796
+ this._chatClient.config.debug = true;
5797
+ }
5798
+ this._debugLog('Stream开始', 'msgId=' + msgId, 'content=' + (content || '').substring(0, 80), 'opts=' + JSON.stringify(requestOptions));
5918
5799
  if (Object.prototype.hasOwnProperty.call(requestOptions, 'conversationId')) {
5919
5800
  this._chatClient.setConversationId(requestOptions.conversationId || null);
5920
5801
  } else if (this._conversationId) {
@@ -6033,6 +5914,7 @@ class AIChatDialog extends HTMLElement {
6033
5914
  }
6034
5915
  }, requestOptions);
6035
5916
  if (response?.success) {
5917
+ this._debugLog('Stream完成', 'ok, conversationId=' + (response.data?.conversationId || this._conversationId), 'textLen=' + streamText.length);
6036
5918
  if (response.data?.conversationId) {
6037
5919
  this._conversationId = response.data.conversationId;
6038
5920
  } else if (this._chatClient.conversationId) {
@@ -6045,6 +5927,7 @@ class AIChatDialog extends HTMLElement {
6045
5927
  streamText = result;
6046
5928
  }
6047
5929
  } else {
5930
+ this._finalizeMsg(msgId, streamText || '(无回复)');
6048
5931
  return;
6049
5932
  }
6050
5933
  this._finalizeMsg(msgId, streamText || '(无回复)');
@@ -6055,12 +5938,14 @@ class AIChatDialog extends HTMLElement {
6055
5938
  }));
6056
5939
  if (this._config?.onMessageReceived) this._config.onMessageReceived(streamText);
6057
5940
  } catch (e) {
5941
+ this._debugWarn('Stream异常', e.name + ': ' + (e.message || ''));
6058
5942
  if (e.name === 'AbortError') {
6059
5943
  this._updateMsg(msgId, '(请求超时或已取消)');
6060
5944
  } else {
6061
5945
  console.error('[AIChatDialog] 流式失败:', e);
6062
5946
  this._updateMsg(msgId, '网络错误: ' + (e.message || '请检查连接'));
6063
5947
  }
5948
+ this._finalizeMsg(msgId, this._messages.find(m => m.id === msgId)?.content || '(无回复)');
6064
5949
  }
6065
5950
  }
6066
5951
  _getStreamTextEl() {
@@ -6093,10 +5978,8 @@ class AIChatDialog extends HTMLElement {
6093
5978
  const idx = this._messages.findIndex(m => m.id === msgId);
6094
5979
  if (idx < 0) return;
6095
5980
  this._messages[idx].content = content;
6096
-
6097
5981
  // Detect if there are runtime events (for typewriter mode check)
6098
5982
  const hasRuntime = !!(this._messages[idx]._runtimeEvents && this._messages[idx]._runtimeEvents.length > 0);
6099
-
6100
5983
  // Accumulate full content
6101
5984
  if (content.startsWith(this._streamFullText)) {
6102
5985
  this._streamFullText = content;
@@ -6157,7 +6040,6 @@ class AIChatDialog extends HTMLElement {
6157
6040
  this.renderMessages();
6158
6041
  }
6159
6042
  }
6160
-
6161
6043
  // 运行时占位符过滤(对齐 portal)
6162
6044
  _isPlaceholder(text) {
6163
6045
  if (!text || typeof text !== 'string') return false;
@@ -6176,14 +6058,31 @@ class AIChatDialog extends HTMLElement {
6176
6058
  } catch (e) {}
6177
6059
  return false;
6178
6060
  }
6179
-
6180
6061
  // 判断错误标记内容(替换脆弱的前缀检查 startsWith('('))
6181
- _ERROR_CONTENT_PATTERNS = ['(请求超时', '(等待AI处理', '(无回复)', '(已停止)', '(AI 处理超时', '错误:', '网络错误:', '抱歉,'];
6182
6062
  _isErrorContent(content) {
6183
6063
  if (!content) return true;
6184
6064
  return this._ERROR_CONTENT_PATTERNS.some(p => content.startsWith(p));
6185
6065
  }
6186
-
6066
+ // P3: 将上下文对象格式化为可读文本(拼入 prompt 前缀)
6067
+ _formatContextText(context) {
6068
+ if (!context || typeof context !== 'object') return '';
6069
+ const lines = ['[页面上下文]'];
6070
+ for (const key in context) {
6071
+ if (!Object.prototype.hasOwnProperty.call(context, key)) continue;
6072
+ const val = context[key];
6073
+ if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'object') {
6074
+ lines.push(key + ':');
6075
+ for (const item of val) {
6076
+ lines.push(' - ' + Object.values(item).join(' | '));
6077
+ }
6078
+ } else if (typeof val === 'object' && val !== null) {
6079
+ lines.push(key + ': ' + JSON.stringify(val));
6080
+ } else {
6081
+ lines.push(key + ': ' + val);
6082
+ }
6083
+ }
6084
+ return lines.join('\n');
6085
+ }
6187
6086
  // 运行时事件管理 – incremental DOM, no renderMessages
6188
6087
  _addRuntimeEvent(msgId, event) {
6189
6088
  const idx = this._messages.findIndex(m => m.id === msgId);
@@ -6211,7 +6110,6 @@ class AIChatDialog extends HTMLElement {
6211
6110
  if (this._shouldAutoScroll()) this.scrollToBottom();
6212
6111
  return;
6213
6112
  }
6214
-
6215
6113
  // Path 2: first event – inject runtime panel DOM next to the streaming bubble
6216
6114
  const msgContent = this._findStreamingMessageContent();
6217
6115
  if (msgContent) {
@@ -6278,6 +6176,28 @@ class AIChatDialog extends HTMLElement {
6278
6176
  panel.appendChild(eventsContainer);
6279
6177
  return panel;
6280
6178
  }
6179
+ // P4: 获取自定义操作按钮列表(缓存结果避免重复调用 onMessageActions)
6180
+ _getCustomActions(msg, idx) {
6181
+ const key = '_customActions_' + idx;
6182
+ if (!msg[key] && typeof this._config?.onMessageActions === 'function') {
6183
+ try {
6184
+ msg[key] = this._config.onMessageActions(msg, idx) || [];
6185
+ } catch (e) {
6186
+ console.warn('[AIChatDialog] onMessageActions 执行失败:', e);
6187
+ msg[key] = [];
6188
+ }
6189
+ }
6190
+ return msg[key] || [];
6191
+ }
6192
+ // P4: 生成自定义操作按钮 HTML
6193
+ _buildCustomActions(msg, idx) {
6194
+ const actions = this._getCustomActions(msg, idx);
6195
+ if (!actions.length) return '';
6196
+ return actions.map((a, i) => {
6197
+ const cls = a.className || '';
6198
+ return '<span class="action-icon custom-action-btn' + (cls ? ' ' + this.escapeAttr(cls) : '') + '" data-idx="' + idx + '" data-action="' + i + '" title="' + this.escapeAttr(a.label) + '">' + this.escapeHtml(a.label) + '</span>';
6199
+ }).join('');
6200
+ }
6281
6201
  _buildRuntimePanel(msg, msgIdx) {
6282
6202
  const events = msg._runtimeEvents || [];
6283
6203
  if (events.length === 0) return '';
@@ -6294,7 +6214,7 @@ class AIChatDialog extends HTMLElement {
6294
6214
  }
6295
6215
  async _fetchConversationResult(conversationId) {
6296
6216
  for (let i = 0; i < 8; i++) {
6297
- await new Promise(r => setTimeout(r, 1000));
6217
+ await new Promise(r => window.setTimeout(r, 1000));
6298
6218
  try {
6299
6219
  const response = await this._chatClient.queryConversation({
6300
6220
  conversationId,
@@ -6310,11 +6230,9 @@ class AIChatDialog extends HTMLElement {
6310
6230
  }
6311
6231
  return '(AI 处理超时,请稍后查看对话记录)';
6312
6232
  }
6313
-
6314
6233
  // ==================== 重新生成(与Vue regenerate 一致) ====================
6315
-
6316
6234
  async regenerate(index) {
6317
- if (this._isLoading) return;
6235
+ if (this._isLoading || this._streaming) return;
6318
6236
  const aiMessage = this._messages[index];
6319
6237
  if (!aiMessage || aiMessage.type !== 'ai') return;
6320
6238
  let userQuestion = '';
@@ -6357,14 +6275,12 @@ class AIChatDialog extends HTMLElement {
6357
6275
  toast.className = 'error-toast';
6358
6276
  toast.textContent = msg;
6359
6277
  this._dialog?.appendChild(toast);
6360
- setTimeout(() => toast.remove(), 3000);
6278
+ window.setTimeout(() => toast.remove(), 3000);
6361
6279
  }
6362
-
6363
6280
  // P1-6: 精细化错误处理(与Vue版 handleErrorMsg 一致,按HTTP状态码+业务错误码分类)
6364
6281
  handleError(err) {
6365
6282
  let displayMsg = '抱歉,网络请求失败,请稍后重试';
6366
6283
  const errMsg = err?.message || '';
6367
-
6368
6284
  // 按错误类型分类
6369
6285
  if (errMsg.includes('Failed to fetch') || errMsg.includes('NetworkError') || errMsg.includes('网络')) {
6370
6286
  displayMsg = '网络连接失败,请检查网络后重试';
@@ -6398,9 +6314,7 @@ class AIChatDialog extends HTMLElement {
6398
6314
  detail: err
6399
6315
  }));
6400
6316
  }
6401
-
6402
6317
  // ==================== 复制(与Vue copyMessage 一致) ====================
6403
-
6404
6318
  async copyContent(text) {
6405
6319
  // P1-10: 微信环境优先使用 wx.setClipboardData(与Vue版一致)
6406
6320
  if (typeof wx !== 'undefined' && wx.setClipboardData) {
@@ -6443,7 +6357,7 @@ class AIChatDialog extends HTMLElement {
6443
6357
  await this.copyContent(content);
6444
6358
  if (this._messages[idx]) this._messages[idx].copied = true;
6445
6359
  this.renderMessages();
6446
- setTimeout(() => {
6360
+ window.setTimeout(() => {
6447
6361
  if (this._messages[idx]) {
6448
6362
  this._messages[idx].copied = false;
6449
6363
  this.renderMessages();
@@ -6492,9 +6406,7 @@ class AIChatDialog extends HTMLElement {
6492
6406
  }
6493
6407
  return response;
6494
6408
  }
6495
-
6496
6409
  // ==================== 工具函数 ====================
6497
-
6498
6410
  generateId() {
6499
6411
  return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
6500
6412
  }
@@ -6502,6 +6414,19 @@ class AIChatDialog extends HTMLElement {
6502
6414
  const n = new Date();
6503
6415
  return `${String(n.getHours()).padStart(2, '0')}:${String(n.getMinutes()).padStart(2, '0')}`;
6504
6416
  }
6417
+ /**
6418
+ * 调试日志(仅在 config.debug === true 时输出)
6419
+ */
6420
+ _debugLog(tag, ...args) {
6421
+ if (this._config?.debug) {
6422
+ console.log('%c[AI-SDK]%c ' + tag, 'color:#2563eb;font-weight:600', 'color:inherit', ...args);
6423
+ }
6424
+ }
6425
+ _debugWarn(tag, ...args) {
6426
+ if (this._config?.debug) {
6427
+ console.warn('%c[AI-SDK]%c ' + tag, 'color:#f59e0b;font-weight:600', 'color:inherit', ...args);
6428
+ }
6429
+ }
6505
6430
  escapeHtml(s) {
6506
6431
  if (!s) return '';
6507
6432
  const d = document.createElement('div');
@@ -6512,7 +6437,6 @@ class AIChatDialog extends HTMLElement {
6512
6437
  if (!s) return '';
6513
6438
  return s.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
6514
6439
  }
6515
-
6516
6440
  /**
6517
6441
  * 重置 _themeVars 为默认值(主题切换时调用,防止残留)
6518
6442
  */
@@ -6554,7 +6478,6 @@ class AIChatDialog extends HTMLElement {
6554
6478
  '--ai-font-small': '11px'
6555
6479
  });
6556
6480
  }
6557
-
6558
6481
  /**
6559
6482
  * Markdown → HTML 解析(仅用于AI回复,用户消息保持纯文本)
6560
6483
  * 使用 marked + DOMPurify 双重保障安全
@@ -6578,7 +6501,6 @@ class AIChatDialog extends HTMLElement {
6578
6501
  }
6579
6502
  }
6580
6503
  }
6581
-
6582
6504
  // 注册自定义元素
6583
6505
  if (!customElements.get('ai-chat-dialog')) {
6584
6506
  customElements.define('ai-chat-dialog', AIChatDialog);
@@ -6590,17 +6512,15 @@ if (typeof window !== 'undefined') {
6590
6512
  /**
6591
6513
  * IBC AI Web SDK - 纯JavaScript版本
6592
6514
  * 支持任意前端框架:Vue, React, Angular, 原生HTML等
6593
- *
6515
+ *
6594
6516
  * @author IBC AI Team
6595
- * @version 2.0.4
6517
+ * @version 2.1.0
6596
6518
  */
6597
-
6598
-
6519
+ // 导出组件
6599
6520
  // 快速初始化函数
6600
6521
  function createAIChatDialog(options = {}) {
6601
6522
  // 创建自定义元素实例
6602
6523
  const dialog = document.createElement('ai-chat-dialog');
6603
-
6604
6524
  // 设置属性
6605
6525
  if (options.title) dialog.setAttribute('title', options.title);
6606
6526
  if (options.placeholder) dialog.setAttribute('placeholder', options.placeholder);
@@ -6609,7 +6529,6 @@ function createAIChatDialog(options = {}) {
6609
6529
  if (options.height) dialog.style.setProperty('--ai-dialog-height', typeof options.height === 'number' ? `${options.height}px` : options.height);
6610
6530
  if (options.top != null) dialog.style.setProperty('--ai-dialog-top', typeof options.top === 'number' ? `${options.top}px` : options.top);
6611
6531
  if (options.right != null) dialog.style.setProperty('--ai-dialog-right', typeof options.right === 'number' ? `${options.right}px` : options.right);
6612
-
6613
6532
  // 挂载到指定容器或 body
6614
6533
  if (options.target) {
6615
6534
  const container = typeof options.target === 'string' ? document.querySelector(options.target) : options.target;
@@ -6623,12 +6542,10 @@ function createAIChatDialog(options = {}) {
6623
6542
  } else {
6624
6543
  document.body.appendChild(dialog);
6625
6544
  }
6626
-
6627
6545
  // 初始化配置
6628
6546
  if (Object.keys(options).length > 0) {
6629
6547
  dialog.init(options);
6630
6548
  }
6631
-
6632
6549
  // 行内模式:挂载到 DOM 后直接展开
6633
6550
  if (options.target) {
6634
6551
  requestAnimationFrame(() => {
@@ -6653,14 +6570,12 @@ function createAIChatDialog(options = {}) {
6653
6570
  }
6654
6571
  return dialog;
6655
6572
  }
6656
-
6657
6573
  // Vue插件安装方式(向后兼容)
6658
6574
  function installVuePlugin(Vue) {
6659
6575
  if (!Vue) {
6660
6576
  console.warn('[AI Web SDK] Vue instance not provided');
6661
6577
  return;
6662
6578
  }
6663
-
6664
6579
  // 注册全局组件包装器
6665
6580
  Vue.component('AiChatWrapper', {
6666
6581
  props: {
@@ -6716,7 +6631,6 @@ function installVuePlugin(Vue) {
6716
6631
  methods: {
6717
6632
  initDialog() {
6718
6633
  this.dialogInstance = createAIChatDialog(this.config || {});
6719
-
6720
6634
  // 监听事件并转发
6721
6635
  const events = ['open', 'close', 'message-send', 'message-received', 'error'];
6722
6636
  events.forEach(event => {
@@ -6744,9 +6658,6 @@ function installVuePlugin(Vue) {
6744
6658
  }
6745
6659
  });
6746
6660
  }
6747
-
6748
- // React Hook(可选) — 通过 window.React 获取 hooks,兼容 CDN 全局引入
6749
- /* global React */
6750
6661
  function useAIChat(options = {}) {
6751
6662
  if (typeof React === 'undefined') {
6752
6663
  console.warn('[AI Web SDK] React is not loaded, useAIChat skipped');
@@ -6770,7 +6681,6 @@ function useAIChat(options = {}) {
6770
6681
  useEffect(() => {
6771
6682
  if (!dialogRef.current) {
6772
6683
  dialogRef.current = createAIChatDialog(options);
6773
-
6774
6684
  // 监听事件
6775
6685
  dialogRef.current.addEventListener('message-send', e => {
6776
6686
  setMessages(prev => [...prev, e.detail]);
@@ -6809,12 +6719,10 @@ function useAIChat(options = {}) {
6809
6719
  },
6810
6720
  sendMessage: content => {
6811
6721
  if (dialogRef.current) {
6812
- const input = dialogRef.current.shadowRoot?.querySelector('.ai-textarea');
6722
+ const input = dialogRef.current.shadowRoot?.querySelector('.message-input');
6813
6723
  if (input) {
6814
- input.value = content;
6815
- input.dispatchEvent(new Event('input'));
6724
+ dialogRef.current.send?.(content) || (input.value = content, input.dispatchEvent(new Event('input')), dialogRef.current.shadowRoot?.querySelector('.send-btn')?.click());
6816
6725
  }
6817
- dialogRef.current.handleSend?.() || dialogRef.current.shadowRoot?.querySelector('.ai-send-btn')?.click();
6818
6726
  }
6819
6727
  },
6820
6728
  clearMessages: () => {
@@ -6827,7 +6735,6 @@ function useAIChat(options = {}) {
6827
6735
  ref: dialogRef
6828
6736
  };
6829
6737
  }
6830
-
6831
6738
  // 默认导出
6832
6739
  var index = {
6833
6740
  AIChatDialog,
@@ -6835,14 +6742,13 @@ var index = {
6835
6742
  createAIChatDialog,
6836
6743
  installVuePlugin,
6837
6744
  useAIChat,
6838
- version: '2.0.4'
6745
+ version: '2.1.0'
6839
6746
  };
6840
-
6841
6747
  // 全局暴露(UMD/浏览器环境)
6842
6748
  if (typeof window !== 'undefined') {
6843
6749
  window.AICreateChatDialog = createAIChatDialog;
6844
6750
  window.AIWebSDK = {
6845
- version: '2.0.4',
6751
+ version: '2.1.0',
6846
6752
  create: createAIChatDialog,
6847
6753
  AIChatDialog,
6848
6754
  AIChatClient,