@lofcz/platejs-ai 52.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["ExtendConfig","toPlatePlugin","BaseAIPluginConfig","BaseAIPlugin","AIPluginConfig","AIPlugin","distance","NodeEntry","Path","Range","NodeApi","maxAllowedDistance","len","findTextRangeInBlock","block","findText","blockNode","blockPath","textSegments","offset","path","text","fullText","textNode","textPath","texts","startOffset","length","absolutePath","push","matchStart","indexOf","matchEnd","maxDist","bestMatch","Number","POSITIVE_INFINITY","end","start","i","lenOffset","candidate","slice","dist","prefixLen","prefix","Math","max","idx","findPoint","charOffset","isEnd","segment","segmentEnd","localOffset","lastSegment","at","anchor","focus","deserializeMd","NodeEntry","Range","SlateEditor","TElement","NodeApi","TComment","findTextRangeInBlock","aiCommentToRange","editor","aiComment","blockId","content","contentNodes","firstBlock","ranges","forEach","node","index","currentBlock","api","id","at","_","firstBlockPath","blockPath","range","block","findText","string","push","length","startRange","endRange","anchor","focus","PlateEditor","acceptSuggestion","getSuggestionKey","getTransientSuggestionKey","SuggestionPlugin","acceptAISuggestions","editor","suggestions","getApi","suggestion","nodes","transient","forEach","suggestionNode","suggestionData","description","createdAt","Date","keyId","id","suggestionId","type","userId","tf","unsetNodes","at","mode","match","n","KEYS","PlateEditor","getEditorPlugin","withAIBatch","AIPlugin","AIChatPluginConfig","AIChatPlugin","acceptAISuggestions","acceptAIChat","editor","mode","getOption","tf","api","getApi","key","ai","lastAINodePath","aiChat","node","at","reverse","removeMarks","getTransforms","removeAnchor","hide","focus","focusPoint","end","setSelection","anchor","KEYS","Descendant","TElement","TTableCellElement","TTableElement","TTableRowElement","isSingleCellTable","nodes","length","table","type","rows","children","row","tr","cells","cell","td","getTableCellChildren","deserializeMd","BlockSelectionPlugin","diffToSuggestions","getTransientSuggestionKey","SkipSuggestionDeletes","Descendant","SlateEditor","TElement","TIdElement","TSuggestionData","TSuggestionElement","ElementApi","KEYS","nanoid","TextApi","AIChatPlugin","getTableCellChildren","withoutTable","isSingleCellTable","applyAISuggestions","editor","content","getApi","key","cursorOverlay","removeCursor","chatNodes","getOptions","length","setReplaceIds","ids","setOption","getOption","map","node","id","diffNodes","getDiffNodes","replaceNodes","Array","from","api","nodes","at","match","n","isElement","includes","forEach","path","index","diffNode","tf","slice","replaceNode","diffSuggestion","isSameString","isSameSuggestion","suggestion","type","blockSelection","set","insertFragment","mode","isText","range","nodesRange","setSelection","withProps","originalNode","children","withTransient","withoutSuggestionAndComments","comment","text","nodeWithoutSuggestion","Object","keys","startsWith","aiContent","rawChatNodes","aiNodes","ignoreProps","deserializeMd","diffToSuggestions","SlateEditor","TElement","ElementApi","withoutSuggestionAndComments","withTransient","TableCellUpdate","content","id","applyTableCellSuggestion","editor","cellUpdate","cellEntry","api","node","at","match","n","isElement","console","warn","cell","cellPath","originalChildren","children","aiNodes","diffNodes","ignoreProps","transientDiffNodes","tf","replaceNodes","PlateEditor","usePluginOption","AIChatPlugin","getLastAssistantMessage","editor","messages","getOptions","chat","findLast","message","role","useLastAssistantMessage","$","_c","toolName","t0","_temp","PlateEditor","getSuggestionKey","getTransientSuggestionKey","rejectSuggestion","SuggestionPlugin","rejectAISuggestions","editor","suggestions","getApi","suggestion","nodes","transient","forEach","suggestionNode","suggestionData","description","createdAt","Date","keyId","id","suggestionId","type","userId","tf","unsetNodes","at","mode","match","n","KEYS","PlateEditor","getEditorPlugin","AIChatPluginConfig","AIPlugin","resetAIChat","editor","undo","api","getOptions","setOptions","key","aiChat","stop","chat","messages","length","setMessages","_replaceIds","chatNodes","mode","toolName","getTransforms","ai","ChatRequestOptions","isSelecting","BlockSelectionPlugin","Descendant","KEYS","NodeEntry","Range","TIdElement","PlateEditor","getEditorPlugin","AIMode","AIToolName","AIChatPluginConfig","EditorPrompt","getEditorPrompt","AIPlugin","submitAIChat","editor","input","mode","options","prompt","toolName","toolNameProps","getOptions","setOption","key","aiChat","chat","toolNameOption","length","getTransforms","ai","undo","blocks","getApi","blockSelection","getNodes","blocksRange","api","nodesRange","promptText","selection","chatNodes","map","block","selectionBlocks","fragment","ctx","children","sendMessage","text","body","PlateEditor","BlockSelectionPlugin","removeBlockSelectionNodes","cloneDeep","NodeEntry","SlateEditor","TElement","KEYS","NodeApi","TextApi","AIChatPluginConfig","createFormattedBlocks","blocks","format","sourceBlock","sourceNode","firstTextEntry","firstText","blockProps","extractProps","textProps","applyTextFormatting","node","isText","children","map","block","index","replaceSelectionAIChat","editor","sourceEditor","api","isEmpty","isBlockSelecting","getOption","getApi","key","ai","aiChat","hide","firstBlock","mode","isSelected","contains","formattedBlocks","type","codeLine","codeBlock","length","tf","insertFragment","focus","blockSelectionApi","blockSelection","selectedBlocks","getNodes","withoutNormalizing","withNewBatch","getTransforms","insertBlocksAndSelect","at","firstBlockPath","PlateEditor","BlockSelectionPlugin","cloneDeep","NodeEntry","KEYS","PathApi","RangeApi","SlateEditor","TIdElement","withAIBatch","AIPlugin","AIChatPluginConfig","AIChatPlugin","acceptAISuggestions","createFormattedBlocks","insertBelowAIChat","editor","sourceEditor","format","toolName","getOptions","insertBelowGenerate","selectedBlocks","getApi","blockSelection","getNodes","selectedIds","getTransforms","ai","undo","insertBlocksAndSelect","size","lastBlock","at","nextPath","next","nodes","map","block","insertedCallback","aiChat","hide","focus","api","isEmpty","isBlockSelecting","getOption","key","children","formattedBlocks","blocks","sourceBlock","end","edges","selection","endPath","path","currentBlock","node","mode","PlateEditor","RemoveNodesOptions","ElementApi","getPluginType","KEYS","removeAnchorAIChat","editor","options","tf","withoutSaving","removeNodes","at","match","n","isElement","type","aiChat","OverrideEditor","ElementApi","KEYS","AIPlugin","AIChatPluginConfig","AIChatPlugin","withAIChat","api","editor","getOptions","tf","insertText","normalizeNode","type","getTransforms","matchesTrigger","text","trigger","RegExp","test","Array","isArray","includes","transforms","options","triggerPreviousCharPattern","triggerQuery","fn","selection","previousChar","string","range","matchesPreviousCharPattern","nodeEntry","block","highest","isEmpty","aiChat","show","entry","node","path","ai","open","removeMarks","at","isElement","removeAnchor","UseChatHelpers","TriggerComboboxPluginOptions","BlockSelectionPlugin","EditorNodesOptions","NodeEntry","OmitFirst","Path","PluginConfig","SlateEditor","TIdElement","TRange","bindFirst","ElementApi","getPluginType","KEYS","createTPlatePlugin","AIBatch","AIMode","AIToolName","ChatMessage","AIPlugin","removeAnchorAIChat","acceptAIChat","insertBelowAIChat","replaceSelectionAIChat","resetAIChat","submitAIChat","withAIChat","AIChatPluginConfig","_blockChunks","_blockPath","_mdxName","_replaceIds","aiEditor","chat","chatNodes","chatSelection","experimental_lastTextId","mode","open","streaming","toolName","aiChat","reset","submit","hide","options","focus","undo","node","anchor","reload","show","stop","accept","insertBelow","replaceSelection","removeAnchor","AIChatPlugin","key","dependencies","isElement","messages","trigger","triggerPreviousCharPattern","overrideEditor","extendApi","Pick","editor","getOption","getOptions","setOption","type","rest","api","at","match","n","path","reverse","t","ai","getTransforms","tf","setSelection","getApi","blockSelection","set","map","id","blocks","getNodes","selection","length","nodesRange","ctx","children","regenerate","body","lastBatch","history","undos","undefined","setMessages","extendTransforms","useEffect","useMemo","SlateEditor","DeserializeMdOptions","MarkdownPlugin","useEditorPlugin","AIChatPlugin","useAIChatEditor","editor","content","parser","setOption","children","result","getApi","markdown","deserialize","memoize","useEffect","useRef","TText","KEYS","usePluginOption","AIChatPluginConfig","useLastAssistantMessage","useChatChunk","onChunk","onFinish","chunk","isFirst","nodes","text","content","status","key","aiChat","isLoading","parts","find","part","type","insertedTextRef","prevIsLoadingRef","current","slice","length","push","useEffect","NodeEntry","BlockSelectionPlugin","useEditorPlugin","usePluginOption","AIChatPlugin","UseEditorChatOptions","chat","onOpenBlockSelection","blocks","onOpenChange","open","onOpenCursor","onOpenSelection","useEditorChat","editor","blockSelectionApi","getApi","blockSelection","isBlockSelecting","getOption","getNodes","api","isCollapsed","isExpanded","PlateEditor","DeserializeMdOptions","MarkdownPlugin","streamDeserializeInlineMd","editor","text","options","getApi","markdown","deserializeInline","getChunkTrimmed","chunk","direction","str","trimEnd","trimStart","slice","length","isCompleteCodeBlock","trimmed","trim","startsWithCodeBlock","startsWith","endsWithCodeBlock","endsWith","isCompleteMath","startsWithMath","endsWithMath","isCompleteMath","escapeInput","data","res","startsWith","replace","String","raw","TElement","PlateEditor","getListNode","editor","node","listStyleType","listStart","previousNode","api","previous","at","selection","focus","listRestartPolite","PlateEditor","TElement","TText","isDefined","KEYS","LIST_STYLE_TYPE","isSameNode","editor","node1","node2","type","getType","p","PlateEditor","Descendant","ElementApi","SteamInsertChunkOptions","getListNode","nodesWithProps","editor","nodes","options","map","node","isElement","elementProps","children","textProps","text","PlateEditor","DeserializeMdOptions","MarkdownPlugin","TElement","getPluginType","KEYS","TextApi","AIChatPlugin","getChunkTrimmed","escapeInput","statMdxTagRegex","streamDeserializeMd","editor","data","options","input","value","withoutDeserializeInMdx","Array","isArray","blocks","getApi","markdown","deserialize","preserveEmptyParagraphs","trimmedData","lastBlock","at","addNewLine","unshiftNewLine","direction","isCodeBlockOrTable","type","result","length","textNode","text","lastChild","children","isText","Object","keys","pop","push","slice","p","unshift","mdxName","getOption","isMdxEnd","includes","setOption","newMdxName","exec","startsWith","PlateEditor","SerializeMdOptions","MarkdownPlugin","Descendant","ElementApi","getPluginKey","KEYS","TextApi","getChunkTrimmed","isCompleteCodeBlock","isCompleteMath","trimEndHeading","editor","value","trimmedText","headingKeys","Set","h1","h2","h3","h4","h5","h6","lastBlock","at","has","type","isElement","lastTextNode","children","isText","text","newChildren","slice","trimEnd","newLastBlock","streamSerializeMd","options","chunk","optionsValue","restOptions","result","getApi","markdown","serialize","trimmedChunk","endsWith","replace","PlateEditor","Path","SlateEditor","getPluginType","KEYS","NodeApi","PathApi","AIChatPlugin","streamDeserializeInlineMd","streamDeserializeMd","streamSerializeMd","isSameNode","nodesWithProps","SteamInsertChunkOptions","elementProps","textProps","getNextPath","path","length","result","i","next","streamInsertChunk","editor","chunk","options","_blockChunks","_blockPath","getOptions","blocks","getCurrentBlockPath","startBlock","api","node","startInEmptyParagraph","string","type","p","tf","removeNodes","at","insertNodes","nextBlock","select","setOption","nextBlocks","slice","nextPath","lastBlock","lastBlockChunks","value","tempBlockChunks","tempBlocks","console","warn","JSON","stringify","currentBlock","chunkNodes","end","updatedBlock","serializedBlock","blockText","replaceNodes","codeBlock","table","equation","newEndBlockPath","endBlock","getAnchorPreviousPath","anchorNode","getApi","aiChat","anchor","previous","getFocusPath","selection","focus","entry","columnGroup","above","React","KEYS","RenderNodeWrapperProps","getEditorPlugin","CopilotPluginConfig","renderCopilotBelowNodes","editor","copilot","key","renderGhostText","GhostText","getOptions","children","ReactNode","PlateEditor","deserializeInlineMd","KEYS","CopilotPluginConfig","acceptCopilot","editor","suggestionText","getOptions","key","copilot","length","tf","insertFragment","getOriginalFetch","fetch","CallCompletionApiOptions","prompt","api","body","Record","credentials","RequestCredentials","ReturnType","headers","HeadersInit","setAbortController","abortController","AbortController","setCompletion","completion","setError","error","Error","setLoading","loading","onError","onFinish","onResponse","response","Response","Promise","CompleteOptions","Omit","callCompletionApi","res","JSON","stringify","method","signal","catch","ok","text","json","name","GetNextWord","options","text","firstWord","remainingText","nonSpaceRegex","cjkCharRegex","cjkMatchRegex","nonCjkMatchRegex","getNextWord","nonSpaceMatch","exec","firstNonSpaceChar","isCJKChar","test","match","spaces","char","punctuation","slice","length","KEYS","PlateEditor","getEditorPlugin","CopilotPluginConfig","callCompletionApi","triggerCopilotSuggestion","editor","api","getOptions","setOption","key","copilot","completeOptions","getPrompt","isLoading","triggerQuery","aiChat","chat","prompt","length","stop","onFinish","_","completion","setBlockSuggestion","text","setAbortController","controller","setCompletion","setError","error","setLoading","loading","onError","PlateEditor","CopilotPlugin","withoutAbort","editor","fn","setOption","deserializeInlineMd","KEYS","PlateEditor","getEditorPlugin","CopilotPluginConfig","withoutAbort","acceptCopilotNextWord","editor","api","getOptions","key","copilot","getNextWord","suggestionText","length","firstWord","remainingText","text","setBlockSuggestion","tf","insertFragment","OverrideEditor","PlateEditor","serializeInlineMd","Operation","SlateEditor","TRange","RangeApi","CopilotPluginConfig","withoutAbort","CopilotBatch","shouldAbort","getPatchString","editor","operations","string","operation","type","node","text","value","withCopilot","api","getOptions","setOption","tf","apply","insertText","redo","setSelection","undo","writeHistory","prevSelection","transforms","copilot","reject","options","suggestionText","startsWith","withoutMerging","newText","slice","length","topRedo","history","redos","at","prevSuggestion","shouldRemoveText","props","selection","equals","autoTriggerQuery","isFocused","triggerSuggestion","lastUndos","undos","oldText","shouldInsertText","stacks","batch","isLoading","React","DebouncedFunc","serializeMd","debounce","OmitFirst","PluginConfig","TElement","bindFirst","KEYS","NodeApi","PlateEditor","createTPlatePlugin","CompleteOptions","renderCopilotBelowNodes","acceptCopilot","acceptCopilotNextWord","GetNextWord","getNextWord","triggerCopilotSuggestion","withCopilot","CopilotPluginConfig","CompletionState","completeOptions","Partial","debounceDelay","renderGhostText","ReactNode","shouldAbort","suggestionNodeId","suggestionText","autoTriggerQuery","options","editor","getPrompt","triggerQuery","copilot","triggerSuggestion","reject","setBlockSuggestion","text","id","stop","accept","acceptNextWord","isSuggested","abortController","AbortController","completion","error","Error","isLoading","CopilotPlugin","key","handlers","onBlur","api","onMouseDown","getOptions","isEmpty","selection","block","blockAbove","blockString","string","at","contextEntry","highest","value","isExpanded","isEnd","isAt","end","overrideEditor","extendSelectors","extendTransforms","extendApi","Omit","setOption","setOptions","cancel","abort","length","extend","render","belowNodes","shortcuts","keys"],"sources":["../../src/react/ai/AIPlugin.ts","../../src/react/ai/utils/findTextRangeInBlock.tsx","../../src/react/ai/utils/aiCommentToRange.ts","../../src/react/ai-chat/utils/acceptAISuggestions.ts","../../src/react/ai-chat/transforms/acceptAIChat.ts","../../src/react/ai-chat/utils/nestedContainerUtils.ts","../../src/react/ai-chat/utils/applyAISuggestions.ts","../../src/react/ai-chat/utils/applyTableCellSuggestion.ts","../../src/react/ai-chat/utils/getLastAssistantMessage.ts","../../src/react/ai-chat/utils/rejectAISuggestions.ts","../../src/react/ai-chat/utils/resetAIChat.ts","../../src/react/ai-chat/utils/submitAIChat.ts","../../src/react/ai-chat/transforms/replaceSelectionAIChat.ts","../../src/react/ai-chat/transforms/insertBelowAIChat.ts","../../src/react/ai-chat/transforms/removeAnchorAIChat.ts","../../src/react/ai-chat/withAIChat.ts","../../src/react/ai-chat/AIChatPlugin.ts","../../src/react/ai-chat/hooks/useAIChatEditor.ts","../../src/react/ai-chat/hooks/useChatChunk.ts","../../src/react/ai-chat/hooks/useEditorChat.ts","../../src/react/ai-chat/streaming/streamDeserializeInlineMd.ts","../../src/react/ai-chat/streaming/utils/utils.ts","../../src/react/ai-chat/streaming/utils/escapeInput.ts","../../src/react/ai-chat/streaming/utils/getListNode.ts","../../src/react/ai-chat/streaming/utils/isSameNode.ts","../../src/react/ai-chat/streaming/utils/nodesWithProps.ts","../../src/react/ai-chat/streaming/streamDeserializeMd.ts","../../src/react/ai-chat/streaming/streamSerializeMd.ts","../../src/react/ai-chat/streaming/streamInsertChunk.ts","../../src/react/copilot/renderCopilotBelowNodes.tsx","../../src/react/copilot/transforms/acceptCopilot.ts","../../src/react/copilot/utils/callCompletionApi.ts","../../src/react/copilot/utils/getNextWord.ts","../../src/react/copilot/utils/triggerCopilotSuggestion.ts","../../src/react/copilot/utils/withoutAbort.ts","../../src/react/copilot/transforms/acceptCopilotNextWord.ts","../../src/react/copilot/withCopilot.ts","../../src/react/copilot/CopilotPlugin.tsx"],"sourcesContent":["import type { ExtendConfig } from 'platejs';\n\nimport { toPlatePlugin } from 'platejs/react';\n\nimport { type BaseAIPluginConfig, BaseAIPlugin } from '../../lib';\n\nexport type AIPluginConfig = ExtendConfig<BaseAIPluginConfig>;\n\nexport const AIPlugin = toPlatePlugin(BaseAIPlugin);\n","import { distance } from 'fastest-levenshtein';\nimport { type NodeEntry, type Path, type Range, NodeApi } from 'platejs';\n\nfunction maxAllowedDistance(len: number): number {\n if (len <= 2) return 0;\n if (len <= 5) return 1;\n if (len <= 10) return 2;\n if (len <= 20) return 3;\n // Maximum allowed distance is 5, regardless of text length\n return 5;\n}\n\n/** Find text within a block, supporting fuzzy matching. */\nexport function findTextRangeInBlock({\n block,\n findText,\n}: {\n block: NodeEntry;\n findText: string;\n}): Range | null {\n const [blockNode, blockPath] = block;\n\n // Collect all text content and map positions\n const textSegments: { offset: number; path: Path; text: string }[] = [];\n let fullText = '';\n\n // Iterate through all text nodes in the block\n for (const [textNode, textPath] of NodeApi.texts(blockNode)) {\n const startOffset = fullText.length;\n // textPath is relative to blockNode, not absolute\n const absolutePath = [...blockPath, ...textPath];\n textSegments.push({\n offset: startOffset,\n path: absolutePath,\n text: textNode.text,\n });\n fullText += textNode.text;\n }\n\n if (!fullText) return null;\n\n // Try exact match first\n let matchStart = fullText.indexOf(findText);\n let matchEnd = matchStart >= 0 ? matchStart + findText.length : -1;\n\n // If no exact match, try fuzzy matching\n if (matchStart === -1) {\n const maxDist = maxAllowedDistance(findText.length);\n let bestMatch = { distance: Number.POSITIVE_INFINITY, end: -1, start: -1 };\n\n // Sliding window to find best fuzzy match\n for (let i = 0; i <= fullText.length - findText.length; i++) {\n // Try different lengths around the target length\n for (let lenOffset = -maxDist; lenOffset <= maxDist; lenOffset++) {\n const len = findText.length + lenOffset;\n if (len <= 0 || i + len > fullText.length) continue;\n\n const candidate = fullText.slice(i, i + len);\n const dist = distance(candidate, findText);\n\n if (dist <= maxDist && dist < bestMatch.distance) {\n bestMatch = { distance: dist, end: i + len, start: i };\n }\n }\n }\n\n if (bestMatch.start !== -1) {\n matchStart = bestMatch.start;\n matchEnd = bestMatch.end;\n }\n }\n\n // If still no match, try prefix matching as fallback\n if (matchStart === -1) {\n // Find longest prefix match\n for (let prefixLen = findText.length - 1; prefixLen > 0; prefixLen--) {\n const prefix = findText.slice(0, Math.max(0, prefixLen));\n const idx = fullText.indexOf(prefix);\n if (idx !== -1) {\n matchStart = idx;\n matchEnd = idx + prefixLen;\n break;\n }\n }\n }\n\n if (matchStart === -1) return null;\n\n // Convert character offsets to Slate paths and offsets\n const findPoint = (\n charOffset: number,\n isEnd = false\n ): { offset: number; path: Path } => {\n // For start positions, if offset lands exactly at the beginning of a segment, use that segment\n if (!isEnd) {\n for (const segment of textSegments) {\n if (charOffset === segment.offset) {\n return {\n offset: 0,\n path: segment.path,\n };\n }\n }\n }\n\n // Normal search through segments\n for (const segment of textSegments) {\n const segmentEnd = segment.offset + segment.text.length;\n\n if (charOffset >= segment.offset && charOffset <= segmentEnd) {\n const localOffset = charOffset - segment.offset;\n return {\n offset: localOffset,\n path: segment.path,\n };\n }\n }\n\n // Fallback to last position\n const lastSegment = textSegments.at(-1);\n if (!lastSegment) {\n return { offset: 0, path: blockPath };\n }\n return {\n offset: lastSegment.text.length,\n path: lastSegment.path,\n };\n };\n\n const anchor = findPoint(matchStart, false);\n const focus = findPoint(matchEnd, true);\n\n return {\n anchor,\n focus,\n };\n}\n","import { deserializeMd } from '@platejs/markdown';\nimport {\n type NodeEntry,\n type Range,\n type SlateEditor,\n type TElement,\n NodeApi,\n} from 'platejs';\n\nimport type { TComment } from '../../ai-chat/internal/types';\n\nimport { findTextRangeInBlock } from './findTextRangeInBlock';\n\nexport const aiCommentToRange = (\n editor: SlateEditor,\n aiComment: TComment\n): Range | undefined => {\n const { blockId, content } = aiComment;\n\n const contentNodes = deserializeMd(editor, content);\n\n let firstBlock: NodeEntry<TElement> | undefined;\n\n const ranges: Range[] = [];\n contentNodes.forEach((node, index) => {\n let currentBlock: NodeEntry<TElement> | undefined;\n\n if (index === 0) {\n firstBlock = editor.api.node<TElement>({ id: blockId, at: [] });\n currentBlock = firstBlock;\n } else {\n if (!firstBlock) return;\n\n const [_, firstBlockPath] = firstBlock;\n\n const blockPath = [firstBlockPath[0] + index];\n currentBlock = editor.api.node(blockPath);\n }\n\n if (!currentBlock) return;\n\n const range = findTextRangeInBlock({\n block: currentBlock,\n findText: NodeApi.string(node),\n });\n\n if (!range) return;\n\n ranges.push(range);\n });\n\n if (ranges.length === 0) return;\n\n if (ranges.length > 1) {\n const startRange = ranges[0];\n const endRange = ranges.at(-1)!;\n\n return {\n anchor: startRange.anchor,\n focus: endRange.focus,\n };\n }\n\n if (ranges.length === 1) {\n return ranges[0];\n }\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport {\n acceptSuggestion,\n getSuggestionKey,\n getTransientSuggestionKey,\n} from '@platejs/suggestion';\nimport { SuggestionPlugin } from '@platejs/suggestion/react';\n\nexport const acceptAISuggestions = (editor: PlateEditor) => {\n const suggestions = editor.getApi(SuggestionPlugin).suggestion.nodes({\n transient: true,\n });\n\n suggestions.forEach(([suggestionNode]: [any, any]) => {\n const suggestionData = editor\n .getApi(SuggestionPlugin)\n .suggestion.suggestionData(suggestionNode);\n\n if (!suggestionData) return;\n\n const description = {\n createdAt: new Date(suggestionData.createdAt),\n keyId: getSuggestionKey(suggestionData.id),\n suggestionId: suggestionData.id,\n type: suggestionData.type,\n userId: suggestionData.userId,\n };\n\n acceptSuggestion(editor, description);\n });\n\n editor.tf.unsetNodes([getTransientSuggestionKey()], {\n at: [],\n mode: 'all',\n match: (n) => !!n[getTransientSuggestionKey()],\n });\n};\n","import { KEYS } from 'platejs';\nimport { type PlateEditor, getEditorPlugin } from 'platejs/react';\n\nimport { withAIBatch } from '../../../lib';\nimport { AIPlugin } from '../../ai/AIPlugin';\nimport { type AIChatPluginConfig, AIChatPlugin } from '../AIChatPlugin';\nimport { acceptAISuggestions } from '../utils/acceptAISuggestions';\n\nexport const acceptAIChat = (editor: PlateEditor) => {\n const mode = editor.getOption(AIChatPlugin, 'mode');\n\n if (mode === 'insert') {\n const { tf } = getEditorPlugin(editor, AIPlugin);\n const api = editor.getApi<AIChatPluginConfig>({ key: KEYS.ai });\n\n const lastAINodePath = api.aiChat.node({ at: [], reverse: true })![1];\n\n withAIBatch(editor, () => {\n tf.ai.removeMarks();\n editor.getTransforms(AIChatPlugin).aiChat.removeAnchor();\n });\n\n api.aiChat.hide();\n editor.tf.focus();\n\n const focusPoint = editor.api.end(lastAINodePath)!;\n\n editor.tf.setSelection({\n anchor: focusPoint,\n focus: focusPoint,\n });\n }\n\n if (mode === 'chat') {\n withAIBatch(editor, () => {\n acceptAISuggestions(editor);\n });\n\n editor.getApi(AIChatPlugin).aiChat.hide();\n }\n};\n","import {\n KEYS,\n type Descendant,\n type TElement,\n type TTableCellElement,\n type TTableElement,\n type TTableRowElement,\n} from 'platejs';\n\n/** Check if nodes is a single table with single cell */\nexport const isSingleCellTable = (\n nodes: Descendant[]\n): nodes is [TTableElement] => {\n if (nodes.length !== 1) return false;\n\n const table = nodes[0] as TElement;\n\n if (table.type !== KEYS.table) return false;\n\n const rows = table.children as TElement[];\n\n if (rows.length !== 1) return false;\n\n const row = rows[0] as TElement;\n\n if (row.type !== KEYS.tr) return false;\n\n const cells = row.children as TElement[];\n\n if (cells.length !== 1) return false;\n\n const cell = cells[0] as TElement;\n\n return cell.type === KEYS.td;\n};\n\n/** Extract td children from single-cell table */\nexport const getTableCellChildren = (table: TTableElement): Descendant[] => {\n const row = table.children[0] as TTableRowElement;\n const cell = row.children[0] as TTableCellElement;\n\n return cell.children;\n};\n","import { deserializeMd } from '@platejs/markdown';\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport {\n diffToSuggestions,\n getTransientSuggestionKey,\n SkipSuggestionDeletes,\n} from '@platejs/suggestion';\nimport {\n type Descendant,\n type SlateEditor,\n type TElement,\n type TIdElement,\n type TSuggestionData,\n type TSuggestionElement,\n ElementApi,\n KEYS,\n nanoid,\n TextApi,\n} from 'platejs';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\nimport {\n getTableCellChildren as withoutTable,\n isSingleCellTable,\n} from './nestedContainerUtils';\n\nexport const applyAISuggestions = (editor: SlateEditor, content: string) => {\n /** Conflict with block selection */\n editor\n .getApi({ key: KEYS.cursorOverlay })\n ?.cursorOverlay?.removeCursor('selection');\n\n const { chatNodes } = editor.getOptions(AIChatPlugin);\n\n // Use chatNodes.length to determine if we're in multi-block edit mode\n // instead of checking current selection state (which may have changed)\n if (chatNodes.length > 1) {\n const setReplaceIds = (ids: string[]) => {\n editor.setOption(AIChatPlugin, '_replaceIds', ids);\n };\n\n if (editor.getOption(AIChatPlugin, '_replaceIds').length === 0) {\n setReplaceIds(chatNodes.map((node) => node.id as string));\n }\n\n const diffNodes = getDiffNodes(editor, content);\n\n const replaceNodes = Array.from(\n editor.api.nodes<TIdElement>({\n at: [],\n match: (n: TIdElement) =>\n ElementApi.isElement(n) &&\n editor.getOption(AIChatPlugin, '_replaceIds').includes(n.id),\n })\n );\n\n replaceNodes.forEach(([node, path], index) => {\n const diffNode = diffNodes[index];\n\n // AI returned fewer blocks than original — nothing to apply here.\n if (!diffNode) return;\n\n // When the model outputs more top-level blocks than we currently track,\n // replace the last tracked block with the remaining diff tail in one op.\n if (\n index === replaceNodes.length - 1 &&\n diffNodes.length > replaceNodes.length\n ) {\n editor.tf.replaceNodes(diffNodes.slice(index), {\n at: path,\n });\n return;\n }\n\n const replaceNode = node as unknown as TSuggestionElement;\n const diffSuggestion = diffNode as unknown as TSuggestionElement;\n\n const isSameString =\n SkipSuggestionDeletes(editor, replaceNode) ===\n SkipSuggestionDeletes(editor, diffSuggestion);\n\n const isSameSuggestion =\n (replaceNode.suggestion as TSuggestionData | undefined)?.type ===\n (diffSuggestion.suggestion as TSuggestionData | undefined)?.type;\n\n if (isSameString && isSameSuggestion && node.id === diffNode.id) {\n return;\n }\n\n editor.tf.replaceNodes(diffNode, {\n at: path,\n });\n });\n\n editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.set(diffNodes.map((node) => node.id as string));\n setReplaceIds(diffNodes.map((node) => node.id as string));\n } else {\n const diffNodes = getDiffNodes(editor, content);\n\n editor.tf.insertFragment(diffNodes);\n\n const nodes = Array.from(\n editor.api.nodes({\n at: [],\n mode: 'lowest',\n match: (n) => TextApi.isText(n) && !!n[getTransientSuggestionKey()],\n })\n );\n\n const range = editor.api.nodesRange(nodes);\n\n editor.tf.setSelection(range!);\n\n return;\n }\n};\n\nconst withProps = (\n diffNodes: Descendant[],\n chatNodes: Descendant[]\n): Descendant[] =>\n diffNodes.map((node, index) => {\n if (!ElementApi.isElement(node)) return node;\n\n const originalNode = chatNodes?.[index] as TElement | undefined;\n\n return {\n ...node,\n ...(originalNode ?? { id: nanoid() }),\n children: node.children,\n };\n });\n\nexport const withTransient = (diffNodes: Descendant[]): Descendant[] =>\n diffNodes.map((node) => {\n if (TextApi.isText(node)) {\n return {\n ...node,\n [getTransientSuggestionKey()]: true,\n };\n }\n return {\n ...node,\n children: withTransient(node.children),\n [getTransientSuggestionKey()]: true,\n };\n });\n\nexport const withoutSuggestionAndComments = (\n nodes: Descendant[]\n): Descendant[] =>\n nodes.map((node) => {\n if (TextApi.isText(node)) {\n if (node[KEYS.suggestion] || node[KEYS.comment]) {\n return {\n text: node.text,\n };\n }\n\n return node;\n }\n if (ElementApi.isElement(node)) {\n if (node[KEYS.suggestion]) {\n const nodeWithoutSuggestion: any = {};\n\n Object.keys(node).forEach((key) => {\n if (key !== KEYS.suggestion && !key.startsWith(KEYS.suggestion)) {\n nodeWithoutSuggestion[key] = node[key];\n }\n });\n\n return {\n ...nodeWithoutSuggestion,\n children: withoutSuggestionAndComments(node.children),\n };\n }\n\n return {\n ...node,\n children: withoutSuggestionAndComments(node.children),\n };\n }\n\n return node;\n });\n\nconst getDiffNodes = (editor: SlateEditor, aiContent: string) => {\n /** Original document nodes */\n const rawChatNodes = editor.getOption(AIChatPlugin, 'chatNodes');\n\n let chatNodes = withoutSuggestionAndComments(rawChatNodes);\n\n /**If selecting one single cell table, we just need to compare it's children to get diff nodes */\n if (isSingleCellTable(chatNodes)) {\n chatNodes = withoutTable(chatNodes[0]);\n }\n\n const aiNodes = withProps(deserializeMd(editor, aiContent), chatNodes);\n\n const diffNodes = withTransient(\n diffToSuggestions(editor, chatNodes, aiNodes, {\n ignoreProps: ['id', 'listStart'],\n })\n );\n\n return diffNodes;\n};\n","import { deserializeMd } from '@platejs/markdown';\nimport { diffToSuggestions } from '@platejs/suggestion';\nimport { type SlateEditor, type TElement, ElementApi } from 'platejs';\n\nimport {\n withoutSuggestionAndComments,\n withTransient,\n} from './applyAISuggestions';\n\nexport type TableCellUpdate = {\n content: string;\n id: string;\n};\n\n/**\n * Apply AI-generated content to a table cell as diff suggestions. Finds the\n * cell by ID, deserializes the markdown content, computes diff, and replaces\n * the cell's children with suggestion-marked nodes.\n */\nexport const applyTableCellSuggestion = (\n editor: SlateEditor,\n cellUpdate: TableCellUpdate\n) => {\n const { content, id } = cellUpdate;\n\n // Find the cell by id\n const cellEntry = editor.api.node({\n at: [],\n match: (n) => ElementApi.isElement(n) && n.id === id,\n });\n\n if (!cellEntry) {\n console.warn(`Table cell with id \"${id}\" not found`);\n return;\n }\n\n const [cell, cellPath] = cellEntry as [TElement, number[]];\n\n // Get original cell children (without suggestion marks)\n const originalChildren = withoutSuggestionAndComments(cell.children);\n\n // Deserialize AI content to nodes\n const aiNodes = deserializeMd(editor, content);\n\n // Compute diff\n const diffNodes = diffToSuggestions(editor, originalChildren, aiNodes, {\n ignoreProps: ['id'],\n });\n\n // Add transient suggestion key to all nodes\n const transientDiffNodes = withTransient(diffNodes);\n\n // Replace cell children with diff nodes\n editor.tf.replaceNodes(transientDiffNodes, {\n at: cellPath,\n children: true,\n });\n};\n","import { type PlateEditor, usePluginOption } from 'platejs/react';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\n\nexport function getLastAssistantMessage(editor: PlateEditor) {\n const messages = editor.getOptions(AIChatPlugin).chat.messages;\n\n return messages?.findLast((message) => message.role === 'assistant');\n}\n\nexport function useLastAssistantMessage() {\n const toolName = usePluginOption(AIChatPlugin, 'toolName');\n const chat = usePluginOption(AIChatPlugin, 'chat');\n\n if (toolName === 'comment') return;\n\n return chat.messages?.findLast((message) => message.role === 'assistant');\n}\n","import type { PlateEditor } from 'platejs/react';\n\nimport {\n getSuggestionKey,\n getTransientSuggestionKey,\n rejectSuggestion,\n} from '@platejs/suggestion';\nimport { SuggestionPlugin } from '@platejs/suggestion/react';\n\nexport const rejectAISuggestions = (editor: PlateEditor) => {\n const suggestions = editor.getApi(SuggestionPlugin).suggestion.nodes({\n transient: true,\n });\n\n suggestions.forEach(([suggestionNode]: [any, any]) => {\n const suggestionData = editor\n .getApi(SuggestionPlugin)\n .suggestion.suggestionData(suggestionNode);\n\n if (!suggestionData) return;\n\n const description = {\n createdAt: new Date(suggestionData.createdAt),\n keyId: getSuggestionKey(suggestionData.id),\n suggestionId: suggestionData.id,\n type: suggestionData.type,\n userId: suggestionData.userId,\n };\n\n rejectSuggestion(editor, description);\n });\n\n editor.tf.unsetNodes([getTransientSuggestionKey()], {\n at: [],\n mode: 'all',\n match: (n) => !!n[getTransientSuggestionKey()],\n });\n};\n","import { KEYS } from 'platejs';\nimport { type PlateEditor, getEditorPlugin } from 'platejs/react';\n\nimport type { AIChatPluginConfig } from '../AIChatPlugin';\n\nimport { AIPlugin } from '../../ai/AIPlugin';\n\nexport const resetAIChat = (\n editor: PlateEditor,\n { undo = true }: { undo?: boolean } = {}\n) => {\n const { api, getOptions, setOptions } = getEditorPlugin<AIChatPluginConfig>(\n editor,\n {\n key: KEYS.aiChat,\n }\n );\n\n api.aiChat.stop();\n\n const chat = getOptions().chat;\n\n if (chat.messages && chat.messages.length > 0) {\n chat.setMessages?.([]);\n }\n\n setOptions({\n _replaceIds: [],\n chatNodes: [],\n mode: 'insert',\n toolName: null,\n });\n\n if (undo) {\n editor.getTransforms(AIPlugin).ai.undo();\n }\n};\n","import type { ChatRequestOptions } from 'ai';\n\nimport { isSelecting } from '@platejs/selection';\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport {\n type Descendant,\n KEYS,\n type NodeEntry,\n type Range,\n type TIdElement,\n} from 'platejs';\nimport { type PlateEditor, getEditorPlugin } from 'platejs/react';\n\nimport type { AIMode, AIToolName } from '../../../lib/types';\nimport type { AIChatPluginConfig } from '../AIChatPlugin';\n\nimport {\n type EditorPrompt,\n getEditorPrompt,\n} from '../../../lib/utils/getEditorPrompt';\nimport { AIPlugin } from '../../ai/AIPlugin';\n\nexport const submitAIChat = (\n editor: PlateEditor,\n input: string,\n {\n mode,\n options,\n prompt,\n toolName: toolNameProps,\n }: {\n mode?: AIMode;\n options?: ChatRequestOptions;\n prompt?: EditorPrompt;\n toolName?: AIToolName;\n } = {}\n) => {\n const { getOptions, setOption } = getEditorPlugin<AIChatPluginConfig>(\n editor,\n {\n key: KEYS.aiChat,\n }\n );\n\n const { chat, toolName: toolNameOption } = getOptions();\n\n const toolName = toolNameProps ?? toolNameOption ?? null;\n\n if (!prompt && input?.length === 0) {\n return;\n }\n if (!prompt) {\n prompt = input;\n }\n if (!mode) {\n mode = isSelecting(editor) ? 'chat' : 'insert';\n }\n if (mode === 'insert') {\n editor.getTransforms(AIPlugin).ai.undo();\n }\n\n setOption('mode', mode);\n\n setOption('toolName', toolName);\n\n const blocks: NodeEntry<TIdElement>[] = editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes();\n const blocksRange = editor.api.nodesRange(blocks);\n\n const promptText = getEditorPrompt(editor, {\n prompt,\n });\n\n const selection = blocks.length > 0 ? blocksRange : editor.selection;\n\n let chatNodes: TIdElement[];\n\n if (blocks.length > 0) {\n chatNodes = blocks.map((block) => block[0]) as TIdElement[];\n } else {\n const selectionBlocks = editor.api.blocks({ mode: 'highest' });\n\n if (selectionBlocks.length > 1) {\n chatNodes = selectionBlocks.map((block) => block[0]) as TIdElement[];\n } else {\n chatNodes = editor.api.fragment<TIdElement>();\n }\n }\n\n setOption('chatNodes', chatNodes);\n setOption('chatSelection', blocks.length > 0 ? null : editor.selection);\n\n const ctx: {\n children: Descendant[];\n selection: Range | null;\n toolName: string | null;\n } = {\n children: editor.children,\n selection: selection ?? null,\n toolName,\n };\n\n void chat.sendMessage?.(\n {\n text: promptText,\n },\n {\n body: {\n ctx,\n },\n ...options,\n }\n );\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport {\n BlockSelectionPlugin,\n removeBlockSelectionNodes,\n} from '@platejs/selection/react';\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport {\n type NodeEntry,\n type SlateEditor,\n type TElement,\n KEYS,\n NodeApi,\n TextApi,\n} from 'platejs';\n\nimport type { AIChatPluginConfig } from '../AIChatPlugin';\n\nexport const createFormattedBlocks = ({\n blocks,\n format,\n sourceBlock,\n}: {\n blocks: TElement[];\n format: 'all' | 'none' | 'single';\n sourceBlock: NodeEntry;\n}) => {\n if (format === 'none') return cloneDeep(blocks);\n\n const [sourceNode] = sourceBlock;\n const firstTextEntry = NodeApi.firstText(sourceNode);\n\n if (!firstTextEntry) return null;\n\n const blockProps = NodeApi.extractProps(sourceNode);\n const textProps = NodeApi.extractProps(firstTextEntry[0]);\n\n const applyTextFormatting = (node: any): any => {\n if (TextApi.isText(node)) {\n return { ...textProps, ...node };\n }\n if (node.children) {\n return {\n ...node,\n children: node.children.map(applyTextFormatting),\n };\n }\n\n return node;\n };\n\n return blocks.map((block, index) => {\n if (format === 'single' && index > 0) {\n return block;\n }\n\n return applyTextFormatting({\n ...block,\n ...blockProps,\n });\n });\n};\n\nexport const replaceSelectionAIChat = (\n editor: PlateEditor,\n sourceEditor: SlateEditor,\n { format = 'single' }: { format?: 'all' | 'none' | 'single' } = {}\n) => {\n if (!sourceEditor || sourceEditor.api.isEmpty()) return;\n\n const isBlockSelecting = editor.getOption(\n BlockSelectionPlugin,\n 'isSelectingSome'\n );\n\n editor.getApi<AIChatPluginConfig>({ key: KEYS.ai }).aiChat.hide();\n\n // If no blocks selected, treat it like a normal selection replacement\n if (!isBlockSelecting) {\n const firstBlock = editor.api.node({\n block: true,\n mode: 'lowest',\n });\n\n if (\n firstBlock &&\n editor.api.isSelected(firstBlock[1], { contains: true }) &&\n format !== 'none'\n ) {\n const formattedBlocks = createFormattedBlocks({\n blocks: cloneDeep(sourceEditor.children),\n format,\n sourceBlock: firstBlock,\n });\n\n if (!formattedBlocks) return;\n\n /** When user selection is cover the whole code block */\n if (\n firstBlock[0].type === KEYS.codeLine &&\n sourceEditor.children[0].type === KEYS.codeBlock &&\n sourceEditor.children.length === 1\n ) {\n editor.tf.insertFragment(formattedBlocks[0].children);\n } else {\n editor.tf.insertFragment(formattedBlocks);\n }\n\n editor.tf.focus();\n\n return;\n }\n\n editor.tf.insertFragment(sourceEditor.children);\n editor.tf.focus();\n\n return;\n }\n\n const blockSelectionApi = editor.getApi(BlockSelectionPlugin).blockSelection;\n const selectedBlocks = blockSelectionApi.getNodes();\n\n if (selectedBlocks.length === 0) return;\n // If format is 'none' or multiple blocks with 'single',\n // just insert the content as is\n if (format === 'none' || (format === 'single' && selectedBlocks.length > 1)) {\n editor.tf.withoutNormalizing(() => {\n removeBlockSelectionNodes(editor);\n\n editor.tf.withNewBatch(() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.insertBlocksAndSelect(\n cloneDeep(sourceEditor.children),\n {\n at: selectedBlocks[0][1],\n }\n );\n });\n });\n\n editor.getApi(BlockSelectionPlugin).blockSelection.focus();\n\n return;\n }\n\n // Apply formatting from first block when:\n // - formatting is 'all', or\n // - only one block is selected\n const [, firstBlockPath] = selectedBlocks[0];\n const formattedBlocks = createFormattedBlocks({\n blocks: cloneDeep(sourceEditor.children),\n format,\n sourceBlock: selectedBlocks[0],\n });\n\n if (!formattedBlocks) return;\n\n editor.tf.withoutNormalizing(() => {\n removeBlockSelectionNodes(editor);\n\n editor.tf.withNewBatch(() => {\n editor\n .getTransforms(BlockSelectionPlugin)\n .blockSelection.insertBlocksAndSelect(formattedBlocks, {\n at: firstBlockPath,\n });\n });\n });\n\n editor.getApi(BlockSelectionPlugin).blockSelection.focus();\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport cloneDeep from 'lodash/cloneDeep.js';\nimport {\n type NodeEntry,\n KEYS,\n PathApi,\n RangeApi,\n type SlateEditor,\n type TIdElement,\n} from 'platejs';\n\nimport { withAIBatch } from '../../../lib';\nimport { AIPlugin } from '../../ai/AIPlugin';\nimport { type AIChatPluginConfig, AIChatPlugin } from '../AIChatPlugin';\nimport { acceptAISuggestions } from '../utils';\nimport { createFormattedBlocks } from './replaceSelectionAIChat';\n\nexport const insertBelowAIChat = (\n editor: PlateEditor,\n sourceEditor: SlateEditor,\n { format = 'single' }: { format?: 'all' | 'none' | 'single' } = {}\n) => {\n const { toolName } = editor.getOptions(AIChatPlugin);\n\n if (toolName === 'generate')\n return insertBelowGenerate(editor, sourceEditor, { format });\n\n const selectedBlocks: NodeEntry<TIdElement>[] = editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes();\n\n const selectedIds = editor.getOptions(BlockSelectionPlugin).selectedIds;\n\n editor.getTransforms(AIPlugin).ai.undo();\n\n const insertBlocksAndSelect =\n editor.getTransforms(BlockSelectionPlugin).blockSelection\n .insertBlocksAndSelect;\n\n if (!selectedIds || selectedIds.size === 0) return;\n\n const lastBlock = selectedBlocks.at(-1);\n\n if (!lastBlock) return;\n\n const nextPath = PathApi.next(lastBlock[1]);\n\n const nodes = selectedBlocks.map((block) => block[0]);\n\n insertBlocksAndSelect(nodes, {\n at: nextPath,\n insertedCallback: () => {\n withAIBatch(editor, () => {\n acceptAISuggestions(editor);\n });\n },\n });\n\n editor.getApi(AIChatPlugin).aiChat.hide({ focus: false });\n};\n\nexport const insertBelowGenerate = (\n editor: PlateEditor,\n sourceEditor: SlateEditor,\n { format = 'single' }: { format?: 'all' | 'none' | 'single' } = {}\n) => {\n if (!sourceEditor || sourceEditor.api.isEmpty()) return;\n\n const isBlockSelecting = editor.getOption(\n BlockSelectionPlugin,\n 'isSelectingSome'\n );\n\n editor.getApi<AIChatPluginConfig>({ key: KEYS.ai }).aiChat.hide();\n\n const insertBlocksAndSelect =\n editor.getTransforms(BlockSelectionPlugin).blockSelection\n .insertBlocksAndSelect;\n\n if (isBlockSelecting) {\n const selectedBlocks = editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes();\n\n const selectedIds = editor.getOptions(BlockSelectionPlugin).selectedIds;\n\n if (!selectedIds || selectedIds.size === 0) return;\n\n const lastBlock = selectedBlocks.at(-1);\n\n if (!lastBlock) return;\n\n const nextPath = PathApi.next(lastBlock[1]);\n\n if (format === 'none') {\n insertBlocksAndSelect(cloneDeep(sourceEditor.children), {\n at: nextPath,\n });\n\n return;\n }\n\n const formattedBlocks = createFormattedBlocks({\n blocks: cloneDeep(sourceEditor.children),\n format,\n sourceBlock: lastBlock,\n });\n\n if (!formattedBlocks) return;\n\n insertBlocksAndSelect(formattedBlocks, {\n at: nextPath,\n });\n } else {\n const [, end] = RangeApi.edges(editor.selection!);\n const endPath = [end.path[0]];\n const currentBlock = editor.api.node({\n at: endPath,\n block: true,\n mode: 'lowest',\n });\n\n if (!currentBlock) return;\n if (format === 'none') {\n insertBlocksAndSelect(cloneDeep(sourceEditor.children), {\n at: PathApi.next(endPath),\n });\n\n return;\n }\n\n const formattedBlocks = createFormattedBlocks({\n blocks: cloneDeep(sourceEditor.children),\n format,\n sourceBlock: currentBlock,\n });\n\n if (!formattedBlocks) return;\n\n insertBlocksAndSelect(formattedBlocks, {\n at: PathApi.next(endPath),\n });\n }\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport {\n type RemoveNodesOptions,\n ElementApi,\n getPluginType,\n KEYS,\n} from 'platejs';\n\nexport const removeAnchorAIChat = (\n editor: PlateEditor,\n options?: RemoveNodesOptions\n) => {\n editor.tf.withoutSaving(() => {\n editor.tf.removeNodes({\n at: [],\n match: (n) =>\n ElementApi.isElement(n) &&\n n.type === getPluginType(editor, KEYS.aiChat),\n ...options,\n });\n });\n};\n","import type { OverrideEditor } from 'platejs/react';\n\nimport { ElementApi, KEYS } from 'platejs';\n\nimport { AIPlugin } from '../ai/AIPlugin';\nimport { type AIChatPluginConfig, AIChatPlugin } from './AIChatPlugin';\n\nexport const withAIChat: OverrideEditor<AIChatPluginConfig> = ({\n api,\n editor,\n getOptions,\n tf: { insertText, normalizeNode },\n type,\n}) => {\n const tf = editor.getTransforms(AIPlugin);\n\n const matchesTrigger = (text: string) => {\n const { trigger } = getOptions();\n\n if (trigger instanceof RegExp) {\n return trigger.test(text);\n }\n if (Array.isArray(trigger)) {\n return trigger.includes(text);\n }\n\n return text === trigger;\n };\n\n return {\n transforms: {\n insertText(text, options) {\n const { triggerPreviousCharPattern, triggerQuery } = getOptions();\n\n const fn = () => {\n if (\n !editor.selection ||\n !matchesTrigger(text) ||\n (triggerQuery && !triggerQuery(editor))\n ) {\n return;\n }\n\n // Make sure an input is created at the beginning of line or after a whitespace\n const previousChar = editor.api.string(\n editor.api.range('before', editor.selection)\n );\n\n const matchesPreviousCharPattern =\n triggerPreviousCharPattern?.test(previousChar);\n\n if (!matchesPreviousCharPattern) return;\n\n const nodeEntry = editor.api.block({ highest: true });\n\n if (!nodeEntry || !editor.api.isEmpty(nodeEntry[0])) return;\n\n api.aiChat.show();\n\n return true;\n };\n\n if (fn()) return;\n\n return insertText(text, options);\n },\n normalizeNode(entry) {\n const [node, path] = entry;\n\n if (node[KEYS.ai] && !getOptions().open) {\n tf.ai.removeMarks({ at: path });\n\n return;\n }\n\n if (\n ElementApi.isElement(node) &&\n node.type === type &&\n !getOptions().open\n ) {\n editor.getTransforms(AIChatPlugin).aiChat.removeAnchor({ at: path });\n\n return;\n }\n\n return normalizeNode(entry);\n },\n },\n };\n};\n","import type { UseChatHelpers } from '@ai-sdk/react';\nimport type { TriggerComboboxPluginOptions } from '@platejs/combobox';\n\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport {\n type EditorNodesOptions,\n type NodeEntry,\n type OmitFirst,\n type Path,\n type PluginConfig,\n type SlateEditor,\n type TIdElement,\n type TRange,\n bindFirst,\n ElementApi,\n getPluginType,\n KEYS,\n} from 'platejs';\nimport { createTPlatePlugin } from 'platejs/react';\n\nimport type { AIBatch } from '../../lib';\nimport type { AIMode, AIToolName } from '../../lib/types';\nimport type { ChatMessage } from './internal/types';\n\nimport { AIPlugin } from '../ai/AIPlugin';\nimport { removeAnchorAIChat } from './transforms';\nimport { acceptAIChat } from './transforms/acceptAIChat';\nimport { insertBelowAIChat } from './transforms/insertBelowAIChat';\nimport { replaceSelectionAIChat } from './transforms/replaceSelectionAIChat';\nimport { resetAIChat } from './utils/resetAIChat';\nimport { submitAIChat } from './utils/submitAIChat';\nimport { withAIChat } from './withAIChat';\n\nexport type AIChatPluginConfig = PluginConfig<\n 'aiChat',\n {\n _blockChunks: string;\n _blockPath: Path | null;\n /** @private Using For streamInsertChunk */\n _mdxName: string | null;\n _replaceIds: string[];\n /** @private The Editor used to generate the AI response. */\n aiEditor: SlateEditor | null;\n chat: UseChatHelpers<ChatMessage>;\n chatNodes: TIdElement[];\n chatSelection: TRange | null;\n /** @deprecated Use api.aiChat.node({streaming:true}) instead */\n experimental_lastTextId: string | null;\n /**\n * Specifies how the assistant message is handled:\n *\n * - 'insert': Directly inserts content into the editor without preview.\n * - 'chat': Initiates an interactive session to review and refine content\n * before insertion.\n */\n mode: AIMode;\n open: boolean;\n /** Whether the AI response is currently streaming. Cursor mode only. */\n streaming: boolean;\n toolName: AIToolName;\n } & TriggerComboboxPluginOptions,\n {\n aiChat: {\n reset: OmitFirst<typeof resetAIChat>;\n submit: OmitFirst<typeof submitAIChat>;\n hide: (options?: { focus?: boolean; undo?: boolean }) => void;\n node: (\n options?: EditorNodesOptions & { anchor?: boolean; streaming?: boolean }\n ) => NodeEntry | undefined;\n reload: () => void;\n show: () => void;\n stop: () => void;\n };\n },\n {\n aiChat: {\n accept: OmitFirst<typeof acceptAIChat>;\n insertBelow: OmitFirst<typeof insertBelowAIChat>;\n replaceSelection: OmitFirst<typeof replaceSelectionAIChat>;\n removeAnchor: (options?: EditorNodesOptions) => void;\n };\n }\n>;\n\nexport const AIChatPlugin = createTPlatePlugin<AIChatPluginConfig>({\n key: KEYS.aiChat,\n dependencies: ['ai'],\n node: {\n isElement: true,\n },\n options: {\n _blockChunks: '',\n _blockPath: null,\n _mdxName: null,\n _replaceIds: [],\n aiEditor: null,\n chat: { messages: [] } as unknown as UseChatHelpers<ChatMessage>,\n chatNodes: [],\n chatSelection: null,\n experimental_lastTextId: null,\n mode: 'insert',\n open: false,\n streaming: false,\n toolName: null,\n trigger: ' ',\n triggerPreviousCharPattern: /^\\s?$/,\n },\n})\n .overrideEditor(withAIChat)\n .extendApi<\n Pick<\n AIChatPluginConfig['api']['aiChat'],\n 'node' | 'reset' | 'stop' | 'submit'\n >\n >(({ editor, getOption, getOptions, setOption, type }) => ({\n reset: bindFirst(resetAIChat, editor),\n submit: bindFirst(submitAIChat, editor),\n node: (options = {}) => {\n const { anchor = false, streaming = false, ...rest } = options;\n\n if (anchor) {\n return editor.api.node({\n at: [],\n match: (n) => ElementApi.isElement(n) && n.type === type,\n ...rest,\n });\n }\n\n if (streaming) {\n if (!getOption('streaming')) return;\n\n const path = getOption('_blockPath');\n if (!path) return;\n\n return editor.api.node({\n at: path,\n mode: 'lowest',\n reverse: true,\n match: (t) => !!t[getPluginType(editor, KEYS.ai)],\n ...rest,\n });\n }\n\n return editor.api.node({\n match: (n) => n[getPluginType(editor, KEYS.ai)],\n ...rest,\n });\n },\n reload: () => {\n const { chat, chatNodes, chatSelection } = getOptions();\n\n editor.getTransforms(AIPlugin).ai.undo();\n\n if (chatSelection) {\n editor.tf.setSelection(chatSelection);\n } else {\n editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.set(chatNodes.map((node) => node.id as string));\n }\n\n const blocks = editor\n .getApi(BlockSelectionPlugin)\n .blockSelection.getNodes();\n\n const selection =\n blocks.length > 0 ? editor.api.nodesRange(blocks) : editor.selection;\n\n const ctx = {\n children: editor.children,\n selection: selection ?? null,\n toolName: getOption('toolName'),\n };\n\n void chat.regenerate?.({\n body: {\n ctx,\n },\n });\n },\n stop: () => {\n setOption('streaming', false);\n getOptions().chat.stop?.();\n },\n }))\n .extendApi(({ api, editor, getOptions, setOption, tf }) => ({\n hide: ({\n focus = true,\n undo = true,\n }: {\n focus?: boolean;\n undo?: boolean;\n } = {}) => {\n api.aiChat.reset({ undo });\n\n setOption('open', false);\n\n if (focus) {\n if (editor.getOption(BlockSelectionPlugin, 'isSelectingSome')) {\n editor.getApi(BlockSelectionPlugin).blockSelection.focus();\n } else {\n editor.tf.focus();\n }\n }\n\n const lastBatch = editor.history.undos.at(-1) as AIBatch;\n\n if (lastBatch?.ai) {\n lastBatch.ai = undefined;\n }\n\n tf.aiChat.removeAnchor();\n },\n show: () => {\n api.aiChat.reset();\n\n setOption('toolName', null);\n\n getOptions().chat.setMessages?.([]);\n\n setOption('open', true);\n },\n }))\n .extendTransforms(({ editor }) => ({\n accept: bindFirst(acceptAIChat, editor),\n insertBelow: bindFirst(insertBelowAIChat, editor),\n removeAnchor: bindFirst(removeAnchorAIChat, editor),\n replaceSelection: bindFirst(replaceSelectionAIChat, editor),\n }));\n","import { useEffect, useMemo } from 'react';\n\nimport type { SlateEditor } from 'platejs';\n\nimport { type DeserializeMdOptions, MarkdownPlugin } from '@platejs/markdown';\nimport { useEditorPlugin } from 'platejs/react';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\n\n/**\n * Register an editor in the AI chat plugin, and deserializes the content into\n * `editor.children` with block-level memoization.\n *\n * @returns Deserialized children to pass as `value` prop to PlateStatic\n */\nexport const useAIChatEditor = (\n editor: SlateEditor,\n content: string,\n { parser }: DeserializeMdOptions = {}\n) => {\n const { setOption } = useEditorPlugin(AIChatPlugin);\n\n const children = useMemo(\n () => {\n const result = editor\n .getApi(MarkdownPlugin)\n .markdown.deserialize(content, {\n memoize: true,\n parser,\n });\n return result;\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [content]\n );\n\n editor.children = children;\n\n useEffect(() => {\n setOption('aiEditor', editor);\n }, [editor, setOption]);\n\n return children;\n};\n","import { useEffect, useRef } from 'react';\n\nimport type { TText } from 'platejs';\n\nimport { KEYS } from 'platejs';\nimport { usePluginOption } from 'platejs/react';\n\nimport type { AIChatPluginConfig } from '../AIChatPlugin';\n\nimport { useLastAssistantMessage } from '../utils/getLastAssistantMessage';\n\nexport const useChatChunk = ({\n onChunk,\n onFinish,\n}: {\n onChunk: (chunk: {\n chunk: string;\n isFirst: boolean;\n nodes: TText[];\n text: string;\n }) => void;\n onFinish?: ({ content }: { content: string }) => void;\n}) => {\n const { status } = usePluginOption(\n { key: KEYS.aiChat } as AIChatPluginConfig,\n 'chat'\n );\n const isLoading = status === 'streaming' || status === 'submitted';\n\n const content = useLastAssistantMessage()?.parts.find(\n (part) => part.type === 'text'\n )?.text;\n\n const insertedTextRef = useRef<string>('');\n const prevIsLoadingRef = useRef(isLoading);\n\n useEffect(() => {\n if (!isLoading) {\n insertedTextRef.current = '';\n }\n if (prevIsLoadingRef.current && !isLoading) {\n onFinish?.({ content: content ?? '' });\n }\n\n prevIsLoadingRef.current = isLoading;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isLoading]);\n\n useEffect(() => {\n if (!content) {\n return;\n }\n\n const chunk = content.slice(insertedTextRef.current.length);\n\n const nodes: TText[] = [];\n\n if (chunk) {\n const isFirst = insertedTextRef.current === '';\n\n nodes.push({ text: chunk });\n onChunk({\n chunk,\n isFirst,\n nodes,\n text: content,\n });\n }\n\n insertedTextRef.current = content;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [content]);\n};\n","'use client';\n\nimport { useEffect } from 'react';\n\nimport type { NodeEntry } from 'platejs';\n\nimport { BlockSelectionPlugin } from '@platejs/selection/react';\nimport { useEditorPlugin, usePluginOption } from 'platejs/react';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\n\nexport type UseEditorChatOptions = {\n // @deprecated not used\n chat?: any;\n onOpenBlockSelection?: (blocks: NodeEntry[]) => void;\n onOpenChange?: (open: boolean) => void;\n onOpenCursor?: () => void;\n onOpenSelection?: () => void;\n};\n\nexport const useEditorChat = ({\n onOpenBlockSelection,\n onOpenChange,\n onOpenCursor,\n onOpenSelection,\n}: UseEditorChatOptions) => {\n const { editor } = useEditorPlugin(AIChatPlugin);\n const open = usePluginOption(AIChatPlugin, 'open');\n\n useEffect(() => {\n onOpenChange?.(open);\n\n if (open) {\n if (onOpenBlockSelection) {\n const blockSelectionApi =\n editor.getApi(BlockSelectionPlugin).blockSelection;\n const isBlockSelecting = editor.getOption(\n BlockSelectionPlugin,\n 'isSelectingSome'\n );\n\n if (isBlockSelecting) {\n onOpenBlockSelection(blockSelectionApi.getNodes());\n\n return;\n }\n }\n if (onOpenCursor && editor.api.isCollapsed()) {\n onOpenCursor();\n\n return;\n }\n if (onOpenSelection && editor.api.isExpanded()) {\n onOpenSelection();\n\n return;\n }\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { type DeserializeMdOptions, MarkdownPlugin } from '@platejs/markdown';\n\nexport const streamDeserializeInlineMd = (\n editor: PlateEditor,\n text: string,\n options?: DeserializeMdOptions\n) => editor.getApi(MarkdownPlugin).markdown.deserializeInline(text, options);\n","export const getChunkTrimmed = (\n chunk: string,\n {\n direction = 'right',\n }: {\n direction?: 'left' | 'right';\n } = {}\n) => {\n const str = direction === 'right' ? chunk.trimEnd() : chunk.trimStart();\n\n if (direction === 'right') {\n return chunk.slice(str.length);\n }\n return chunk.slice(0, chunk.length - str.length);\n};\n\nexport function isCompleteCodeBlock(str: string) {\n const trimmed = str.trim();\n\n const startsWithCodeBlock = trimmed.startsWith('```');\n const endsWithCodeBlock = trimmed.endsWith('```');\n\n return startsWithCodeBlock && endsWithCodeBlock;\n}\n\nexport function isCompleteMath(str: string) {\n const trimmed = str.trim();\n\n const startsWithMath = trimmed.startsWith('$$');\n const endsWithMath = trimmed.endsWith('$$');\n\n return startsWithMath && endsWithMath;\n}\n","import { isCompleteMath } from './utils';\n\nexport const escapeInput = (data: string) => {\n let res = data;\n\n // test case: should correctly handle inline math\n if (\n data.startsWith('$$') &&\n !data.startsWith('$$\\n') &&\n !isCompleteMath(data)\n ) {\n res = data.replace('$$', String.raw`\\$\\$`);\n }\n\n return res;\n};\n","import type { TElement } from 'platejs';\nimport type { PlateEditor } from 'platejs/react';\n\nexport const getListNode = (editor: PlateEditor, node: TElement): TElement => {\n if (node.listStyleType && node.listStart) {\n const previousNode = editor.api.previous({\n at: editor.selection?.focus,\n })?.[0];\n\n // if previous node is also an indent list, don't need to do additional work\n if (previousNode?.listStyleType && previousNode?.listStart) {\n return node;\n }\n if (node.listStart === 1) return node;\n\n return {\n ...node,\n listRestartPolite: node.listStart,\n };\n }\n\n return node;\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { type TElement, type TText, isDefined, KEYS } from 'platejs';\n\nconst LIST_STYLE_TYPE = 'listStyleType';\n\nexport const isSameNode = (\n editor: PlateEditor,\n node1: TElement | TText,\n node2: TElement | TText\n) => {\n if (\n node1.type !== editor.getType(KEYS.p) ||\n node2.type !== editor.getType(KEYS.p)\n )\n return node1.type === node2.type;\n\n if (isDefined(node1[LIST_STYLE_TYPE]) || isDefined(node2[LIST_STYLE_TYPE])) {\n return node1[LIST_STYLE_TYPE] === node2[LIST_STYLE_TYPE];\n }\n\n return node1.type === node2.type;\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { type Descendant, ElementApi } from 'platejs';\n\nimport type { SteamInsertChunkOptions } from '../streamInsertChunk';\n\nimport { getListNode } from './getListNode';\n\nexport const nodesWithProps = (\n editor: PlateEditor,\n nodes: Descendant[],\n options: SteamInsertChunkOptions\n): Descendant[] =>\n nodes.map((node): Descendant => {\n if (ElementApi.isElement(node)) {\n return {\n ...getListNode(editor, node),\n ...options.elementProps,\n children: nodesWithProps(editor, node.children, options),\n };\n }\n return {\n ...options.textProps,\n ...node,\n text: node.text,\n };\n });\n","import type { PlateEditor } from 'platejs/react';\n\nimport { type DeserializeMdOptions, MarkdownPlugin } from '@platejs/markdown';\nimport { type TElement, getPluginType, KEYS, TextApi } from 'platejs';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\nimport { getChunkTrimmed } from './utils';\nimport { escapeInput } from './utils/escapeInput';\n\nconst statMdxTagRegex = /<([A-Za-z][A-Za-z0-9._:-]*)(?:\\s[^>]*?)?(?<!\\/)>/;\n\nexport const streamDeserializeMd = (\n editor: PlateEditor,\n data: string,\n options?: DeserializeMdOptions\n) => {\n const input = escapeInput(data);\n\n const value = withoutDeserializeInMdx(editor, input);\n\n if (Array.isArray(value)) return value;\n\n let blocks: TElement[] = [];\n\n blocks = editor.getApi(MarkdownPlugin).markdown.deserialize(input, {\n ...options,\n preserveEmptyParagraphs: false,\n });\n\n const trimmedData = getChunkTrimmed(data);\n\n const lastBlock = blocks.at(-1) as TElement | undefined;\n\n const addNewLine = trimmedData === '\\n\\n';\n const unshiftNewLine =\n getChunkTrimmed(data, { direction: 'left' }) === '\\n\\n';\n\n const isCodeBlockOrTable =\n lastBlock?.type === 'code_block' || lastBlock?.type === 'table';\n\n let result = blocks;\n\n /**\n * Deserialize the sting like `123\\n\\n` will be `123` base on markdown spec\n * but we want to keep the `\\n\\n`\n */\n\n if (\n lastBlock &&\n !isCodeBlockOrTable &&\n trimmedData.length > 0 &&\n !addNewLine\n ) {\n const textNode = [\n {\n text: trimmedData,\n },\n ];\n\n const lastChild = lastBlock.children.at(-1);\n\n /** It’s like normalizing and merging the text nodes. */\n if (\n lastChild &&\n TextApi.isText(lastChild) &&\n Object.keys(lastChild).length === 1\n ) {\n lastBlock.children.pop();\n\n const textNode = [\n {\n text: lastChild.text + trimmedData,\n },\n ];\n\n lastBlock.children.push(...textNode);\n } else {\n lastBlock.children.push(...textNode);\n }\n\n result = [...blocks.slice(0, -1), lastBlock];\n }\n\n if (addNewLine && !isCodeBlockOrTable) {\n result.push({\n children: [{ text: '' }],\n type: KEYS.p,\n });\n }\n\n if (unshiftNewLine && !isCodeBlockOrTable) {\n result.unshift({\n children: [{ text: '' }],\n type: KEYS.p,\n });\n }\n\n return result;\n};\n\nconst withoutDeserializeInMdx = (editor: PlateEditor, input: string) => {\n const mdxName = editor.getOption(AIChatPlugin, '_mdxName');\n\n if (mdxName) {\n const isMdxEnd = input.includes(`</${mdxName}>`);\n\n if (isMdxEnd) {\n editor.setOption(AIChatPlugin, '_mdxName', null);\n return false;\n }\n return [\n {\n children: [\n {\n text: input,\n },\n ],\n type: getPluginType(editor, KEYS.p),\n },\n ];\n }\n const newMdxName = statMdxTagRegex.exec(input)?.[1];\n\n // Avoid incorrect detection in the code block\n if (input.startsWith(`<${newMdxName}`)) {\n editor.setOption(AIChatPlugin, '_mdxName', newMdxName ?? null);\n }\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { type SerializeMdOptions, MarkdownPlugin } from '@platejs/markdown';\nimport {\n type Descendant,\n ElementApi,\n getPluginKey,\n KEYS,\n TextApi,\n} from 'platejs';\n\nimport {\n getChunkTrimmed,\n isCompleteCodeBlock,\n isCompleteMath,\n} from './utils/utils';\n\n// fixes test: should serialize heading with tailing line break\n// fixes test: incomplete line breaks\nconst trimEndHeading = (\n editor: PlateEditor,\n value: Descendant[]\n): { trimmedText: string; value: Descendant[] } => {\n const headingKeys = new Set([\n KEYS.h1,\n KEYS.h2,\n KEYS.h3,\n KEYS.h4,\n KEYS.h5,\n KEYS.h6,\n ]);\n const lastBlock = value.at(-1);\n\n if (\n lastBlock &&\n headingKeys.has(\n (getPluginKey(editor, lastBlock.type as string) ?? lastBlock.type) as any\n ) &&\n ElementApi.isElement(lastBlock)\n ) {\n const lastTextNode = lastBlock.children.at(-1);\n\n if (TextApi.isText(lastTextNode)) {\n const trimmedText = getChunkTrimmed(lastTextNode?.text as string);\n\n // Create a new lastBlock with immutable operations\n const newChildren = [\n ...lastBlock.children.slice(0, -1),\n { text: lastTextNode.text.trimEnd() },\n ];\n\n const newLastBlock = {\n ...lastBlock,\n children: newChildren,\n };\n\n return {\n trimmedText,\n value: [...value.slice(0, -1), newLastBlock],\n };\n }\n }\n\n return { trimmedText: '', value };\n};\n\nexport const streamSerializeMd = (\n editor: PlateEditor,\n options: SerializeMdOptions,\n chunk: string\n) => {\n const { value: optionsValue, ...restOptions } = options;\n const { value } = trimEndHeading(editor, optionsValue ?? editor.children);\n\n let result = '';\n\n result = editor.getApi(MarkdownPlugin).markdown.serialize({\n value,\n ...restOptions,\n });\n\n const trimmedChunk = getChunkTrimmed(chunk);\n\n if (isCompleteCodeBlock(result) && !chunk.endsWith('```')) {\n result = result.trimEnd().slice(0, -3) + trimmedChunk;\n }\n\n if (isCompleteMath(result) && !chunk.endsWith('$$')) {\n result = result.trimEnd().slice(0, -3) + trimmedChunk;\n }\n\n // clean HTML spaces and zero-width characters\n result = result.replace(/&#x20;/g, ' ');\n result = result.replace(/&#x200B;/g, ' ');\n result = result.replace(/\\u200B/g, '');\n\n // remove extra \\n but not include \\n itself\n // FIXME maybe failed when chunk is more than two'\\n'\n if (trimmedChunk !== '\\n\\n') {\n result = result.trimEnd() + trimmedChunk;\n }\n\n // Handle empty paragraph case for streaming\n if (chunk.endsWith('\\n\\n')) {\n if (result === '\\n') {\n // Single empty paragraph case\n result = '';\n } else if (result.endsWith('\\n\\n')) {\n // Multiple paragraphs ending with empty paragraph\n result = result.slice(0, -1);\n }\n }\n\n // replace &#x20; to real space\n\n // remove Markdown escape characters (including those potentially added in the chunk)\n result = result.replace(/\\\\([\\\\`*_{}\\\\[\\]()#+\\-\\\\.!~<>|$])/g, '$1');\n\n return result;\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport {\n type Path,\n type SlateEditor,\n getPluginType,\n KEYS,\n NodeApi,\n PathApi,\n} from 'platejs';\n\nimport { AIChatPlugin } from '../AIChatPlugin';\nimport { streamDeserializeInlineMd } from './streamDeserializeInlineMd';\nimport { streamDeserializeMd } from './streamDeserializeMd';\nimport { streamSerializeMd } from './streamSerializeMd';\nimport { isSameNode } from './utils/isSameNode';\nimport { nodesWithProps } from './utils/nodesWithProps';\n\nexport type SteamInsertChunkOptions = {\n elementProps?: any;\n textProps?: any;\n};\n\nconst getNextPath = (path: Path, length: number) => {\n let result = path;\n\n for (let i = 0; i < length; i++) {\n result = PathApi.next(result);\n }\n return result;\n};\n\n/** @experimental */\nexport function streamInsertChunk(\n editor: PlateEditor,\n chunk: string,\n options: SteamInsertChunkOptions = {}\n) {\n const { _blockChunks, _blockPath } = editor.getOptions(AIChatPlugin);\n\n if (_blockPath === null) {\n const blocks = streamDeserializeMd(editor, chunk);\n const path = getCurrentBlockPath(editor);\n const startBlock = editor.api.node(path)![0];\n\n const startInEmptyParagraph =\n NodeApi.string(startBlock).length === 0 &&\n startBlock.type === getPluginType(editor, KEYS.p);\n\n // if start in empty paragraph, remove it\n if (startInEmptyParagraph) {\n editor.tf.removeNodes({ at: path });\n }\n\n if (blocks.length > 0) {\n editor.tf.insertNodes(nodesWithProps(editor, [blocks[0]], options), {\n at: path,\n nextBlock: !startInEmptyParagraph,\n select: true,\n });\n\n editor.setOption(AIChatPlugin, '_blockPath', getCurrentBlockPath(editor));\n editor.setOption(AIChatPlugin, '_blockChunks', chunk);\n\n if (blocks.length > 1) {\n const nextBlocks = blocks.slice(1);\n\n const nextPath = getCurrentBlockPath(editor);\n\n editor.tf.insertNodes(nodesWithProps(editor, nextBlocks, options), {\n at: nextPath,\n nextBlock: true,\n select: true,\n });\n\n const lastBlock = editor.api.node(\n getNextPath(nextPath, nextBlocks.length)\n )!;\n\n editor.setOption(AIChatPlugin, '_blockPath', lastBlock[1]);\n\n const lastBlockChunks = streamSerializeMd(\n editor,\n {\n value: [lastBlock[0]],\n },\n chunk\n );\n\n editor.setOption(AIChatPlugin, '_blockChunks', lastBlockChunks);\n }\n }\n } else {\n const tempBlockChunks = _blockChunks + chunk;\n const tempBlocks = streamDeserializeMd(editor, tempBlockChunks);\n\n // console.log(\n // JSON.stringify(chunk),\n // 'chunk',\n // '-------------------------------------------------------------------------------------------'\n // );\n // console.log(\n // '🚀 ~ Streaming ~ tempBlockChunks:',\n // JSON.stringify(tempBlockChunks)\n // );\n\n // console.log('🚀 ~ Streaming ~ tempBlocks:', JSON.stringify(tempBlocks));\n\n if (tempBlocks.length === 0) {\n return console.warn(\n `unsupport md nodes: ${JSON.stringify(tempBlockChunks)}`\n );\n }\n\n if (tempBlocks.length === 1) {\n const currentBlock = editor.api.node(_blockPath)![0];\n\n // If the types are the same\n if (isSameNode(editor, currentBlock, tempBlocks[0])) {\n const chunkNodes = streamDeserializeInlineMd(editor as any, chunk);\n\n // Deserialize the chunk and add it to the end of the current block\n editor.tf.insertNodes(nodesWithProps(editor, chunkNodes, options), {\n at: editor.api.end(_blockPath),\n select: true,\n });\n\n const updatedBlock = editor.api.node(_blockPath)!;\n const serializedBlock = streamSerializeMd(\n editor,\n {\n value: [updatedBlock[0]],\n },\n tempBlockChunks\n );\n\n const blockText = NodeApi.string(tempBlocks[0]);\n\n // Verify if the editor content matches the chunk\n if (\n serializedBlock === tempBlockChunks &&\n blockText === serializedBlock\n ) {\n editor.setOption(AIChatPlugin, '_blockChunks', tempBlockChunks);\n } else {\n editor.tf.replaceNodes(\n nodesWithProps(editor, [tempBlocks[0]], options),\n {\n at: _blockPath,\n select: true,\n }\n );\n\n const serializedBlock = streamSerializeMd(\n editor,\n {\n value: [tempBlocks[0]],\n },\n tempBlockChunks\n );\n\n editor.setOption(\n AIChatPlugin,\n '_blockChunks',\n // one block includes multiple children\n tempBlocks[0].type === getPluginType(editor, KEYS.codeBlock) ||\n tempBlocks[0].type === getPluginType(editor, KEYS.table) ||\n tempBlocks[0].type === getPluginType(editor, KEYS.equation)\n ? tempBlockChunks\n : serializedBlock\n );\n }\n } else {\n const serializedBlock = streamSerializeMd(\n editor,\n {\n value: [tempBlocks[0]],\n },\n tempBlockChunks\n );\n\n editor.tf.replaceNodes(\n nodesWithProps(editor, [tempBlocks[0]], options),\n {\n at: _blockPath,\n select: true,\n }\n );\n\n editor.setOption(AIChatPlugin, '_blockChunks', serializedBlock);\n }\n } else {\n editor.tf.replaceNodes(nodesWithProps(editor, [tempBlocks[0]], options), {\n at: _blockPath,\n select: true,\n });\n\n if (tempBlocks.length > 1) {\n const newEndBlockPath = getNextPath(_blockPath, tempBlocks.length - 1);\n\n editor.tf.insertNodes(\n nodesWithProps(editor, tempBlocks.slice(1), options),\n {\n at: PathApi.next(_blockPath),\n select: true,\n }\n );\n\n editor.setOption(AIChatPlugin, '_blockPath', newEndBlockPath);\n\n const endBlock = editor.api.node(newEndBlockPath)![0];\n\n const serializedBlock = streamSerializeMd(\n editor,\n {\n value: [endBlock],\n },\n tempBlockChunks\n );\n\n editor.setOption(AIChatPlugin, '_blockChunks', serializedBlock);\n }\n }\n }\n}\n\nexport const getCurrentBlockPath = (editor: SlateEditor) => {\n const getAnchorPreviousPath = (editor: SlateEditor): Path | undefined => {\n const anchorNode = editor\n .getApi(AIChatPlugin)\n .aiChat.node({ anchor: true });\n\n if (anchorNode) {\n return PathApi.previous(anchorNode[1])!;\n }\n };\n\n const getFocusPath = (editor: SlateEditor): Path | undefined =>\n editor.selection?.focus.path.slice(0, 1);\n\n const path = getAnchorPreviousPath(editor) ?? getFocusPath(editor) ?? [0];\n\n const entry = editor.api.node(path);\n\n // streaming in table or columns shouldn't remove them\n if (\n entry &&\n (entry[0].type === getPluginType(editor, KEYS.columnGroup) ||\n entry[0].type === getPluginType(editor, KEYS.table))\n ) {\n return editor.api.above()?.[1] ?? path;\n }\n\n return path;\n};\n","'use client';\n\nimport React from 'react';\n\nimport { KEYS } from 'platejs';\nimport { type RenderNodeWrapperProps, getEditorPlugin } from 'platejs/react';\n\nimport type { CopilotPluginConfig } from './CopilotPlugin';\n\nexport const renderCopilotBelowNodes = ({\n editor,\n}: RenderNodeWrapperProps<CopilotPluginConfig>) => {\n const copilot = getEditorPlugin<CopilotPluginConfig>(editor, {\n key: KEYS.copilot,\n });\n\n const { renderGhostText: GhostText } = copilot.getOptions();\n\n if (!GhostText) return;\n\n return ({ children }: { children: React.ReactNode }) => (\n <>\n {children}\n\n <GhostText />\n </>\n );\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { deserializeInlineMd } from '@platejs/markdown';\nimport { KEYS } from 'platejs';\n\nimport type { CopilotPluginConfig } from '../CopilotPlugin';\n\nexport const acceptCopilot = (editor: PlateEditor) => {\n const { suggestionText } = editor.getOptions<CopilotPluginConfig>({\n key: KEYS.copilot,\n });\n\n if (!suggestionText?.length) return false;\n\n editor.tf.insertFragment(deserializeInlineMd(editor, suggestionText));\n};\n","// use function to allow for mocking in tests:\nconst getOriginalFetch = () => fetch;\n\nexport type CallCompletionApiOptions = {\n prompt: string;\n api?: string;\n body?: Record<string, any>;\n credentials?: RequestCredentials | undefined;\n fetch?: ReturnType<typeof getOriginalFetch> | undefined;\n headers?: HeadersInit | undefined;\n setAbortController?: (abortController: AbortController | null) => void;\n setCompletion?: (completion: string) => void;\n setError?: (error: Error | null) => void;\n setLoading?: (loading: boolean) => void;\n onError?: ((error: Error) => void) | undefined;\n onFinish?: ((prompt: string, completion: string) => void) | undefined;\n onResponse?: ((response: Response) => Promise<void> | void) | undefined;\n};\n\nexport type CompleteOptions = Omit<\n CallCompletionApiOptions,\n 'setAbortController' | 'setCompletion' | 'setError' | 'setLoading'\n>;\n\n// https://github.com/vercel/ai/blob/main/packages/ui-utils/src/call-completion-api.ts\n// https://github.com/vercel/ai/blob/642ba22ee33723f3aae9669c7e075322cffca2f3/packages/react/src/use-completion.ts\nexport async function callCompletionApi({\n api = '/api/completion',\n body,\n credentials,\n fetch = getOriginalFetch(),\n headers,\n prompt,\n setAbortController = () => {},\n setCompletion = () => {},\n setError = () => {},\n setLoading = () => {},\n onError,\n onFinish,\n onResponse,\n}: CallCompletionApiOptions) {\n try {\n setLoading(true);\n setError(null);\n\n const abortController = new AbortController();\n setAbortController(abortController);\n\n // Empty the completion immediately.\n setCompletion('');\n\n const res = await fetch(api, {\n body: JSON.stringify({\n prompt,\n ...body,\n }),\n credentials,\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n method: 'POST',\n signal: abortController.signal,\n }).catch((error) => {\n throw error;\n });\n\n if (onResponse) {\n await onResponse(res);\n }\n if (!res.ok) {\n throw new Error(\n (await res.text()) || 'Failed to fetch the chat response.'\n );\n }\n if (!res.body) {\n throw new Error('The response body is empty.');\n }\n\n const { text } = await res.json();\n\n if (!text) {\n throw new Error('The response does not contain a text field.');\n }\n\n setCompletion(text);\n\n if (onFinish) {\n onFinish(prompt, text);\n }\n\n setAbortController(null);\n\n return text as string;\n } catch (error) {\n // Ignore abort errors as they are expected.\n if ((error as any).name === 'AbortError') {\n setAbortController(null);\n\n return null;\n }\n if (error instanceof Error && onError) {\n onError(error);\n }\n\n setError(error as Error);\n } finally {\n setLoading(false);\n }\n}\n","export type GetNextWord = (options: { text: string }) => {\n firstWord: string;\n remainingText: string;\n};\n\nconst nonSpaceRegex = /^\\s*(\\S)/;\nconst cjkCharRegex =\n /[\\u1100-\\u11FF\\u3040-\\u30FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uAC00-\\uD7AF\\uF900-\\uFAFF]/;\nconst cjkMatchRegex =\n /^(\\s*)([\\u1100-\\u11FF\\u3040-\\u30FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uAC00-\\uD7AF\\uF900-\\uFAFF])([\\u3000-\\u303F\\uFF00-\\uFFEF])?/;\nconst nonCjkMatchRegex =\n /^(\\s*\\S+?)(?=[\\s\\u1100-\\u11FF\\u3040-\\u30FF\\u3400-\\u4DBF\\u4E00-\\u9FFF\\uAC00-\\uD7AF\\uF900-\\uFAFF]|$)/;\n\nexport const getNextWord: GetNextWord = ({ text }) => {\n if (!text) return { firstWord: '', remainingText: '' };\n\n // Check if the first non-space character is a CJK character\n const nonSpaceMatch = nonSpaceRegex.exec(text);\n\n if (!nonSpaceMatch) return { firstWord: '', remainingText: '' };\n\n const firstNonSpaceChar = nonSpaceMatch[1];\n\n // Regular expression for matching CJK characters\n // 1. [\\u4E00-\\u9FA5] - Chinese Characters\n // 2. [\\u3040-\\u309F] - Japanese Hiragana\n // 3. [\\u30A0-\\u30FF] - Japanese Katakana\n // 4. [\\u3400-\\u4DBF] - CJK Extension A\n // 5. [\\u4E00-\\u9FFF] - CJK Unified Ideographs\n // 6. [\\uF900-\\uFAFF] - CJK Compatibility Ideographs\n // 7. [\\uAC00-\\uD7AF] - Korean Syllables\n // 8. [\\u1100-\\u11FF] - Korean Jamo\n const isCJKChar = cjkCharRegex.test(firstNonSpaceChar);\n\n let firstWord: string;\n let remainingText: string;\n\n if (isCJKChar) {\n // CJK characters: match leading spaces + first character + optional punctuation\n const match = cjkMatchRegex.exec(text);\n\n if (match) {\n const [, spaces = '', char = '', punctuation = ''] = match;\n firstWord = spaces + char + punctuation;\n remainingText = text.slice(firstWord.length);\n } else {\n firstWord = '';\n remainingText = text;\n }\n } else {\n // For non-CJK text (including mixed content), match until space or CJK char\n const match = nonCjkMatchRegex.exec(text);\n\n if (match) {\n firstWord = match[0];\n remainingText = text.slice(firstWord.length);\n } else {\n firstWord = text;\n remainingText = '';\n }\n }\n\n return { firstWord, remainingText };\n};\n","import { KEYS } from 'platejs';\nimport { type PlateEditor, getEditorPlugin } from 'platejs/react';\n\nimport type { CopilotPluginConfig } from '../CopilotPlugin';\n\nimport { callCompletionApi } from './callCompletionApi';\n\nexport const triggerCopilotSuggestion = async (editor: PlateEditor) => {\n const { api, getOptions, setOption } = getEditorPlugin<CopilotPluginConfig>(\n editor,\n {\n key: KEYS.copilot,\n }\n );\n\n const { completeOptions, getPrompt, isLoading, triggerQuery } = getOptions();\n\n if (isLoading || editor.getOptions({ key: KEYS.aiChat }).chat?.isLoading) {\n return false;\n }\n if (!triggerQuery!({ editor })) return false;\n\n // if (query && !queryEditor(editor, query)) return;\n\n const prompt = getPrompt!({ editor });\n\n if (prompt.length === 0) return false;\n\n api.copilot.stop();\n\n await callCompletionApi({\n prompt,\n onFinish: (_, completion) => {\n api.copilot.setBlockSuggestion({ text: completion });\n },\n ...completeOptions,\n setAbortController: (controller) =>\n setOption('abortController', controller),\n setCompletion: (completion) => setOption('completion', completion),\n setError: (error) => setOption('error', error),\n setLoading: (loading) => setOption('isLoading', loading),\n onError: (error) => {\n setOption('error', error);\n completeOptions?.onError?.(error);\n },\n });\n};\n","import type { PlateEditor } from 'platejs/react';\n\nimport { CopilotPlugin } from '..';\n\nexport const withoutAbort = (editor: PlateEditor, fn: () => void) => {\n editor.setOption(CopilotPlugin, 'shouldAbort', false);\n fn();\n editor.setOption(CopilotPlugin, 'shouldAbort', true);\n};\n","import { deserializeInlineMd } from '@platejs/markdown';\nimport { KEYS } from 'platejs';\nimport { type PlateEditor, getEditorPlugin } from 'platejs/react';\n\nimport type { CopilotPluginConfig } from '../CopilotPlugin';\n\nimport { withoutAbort } from '../utils';\n\nexport const acceptCopilotNextWord = (editor: PlateEditor) => {\n const { api, getOptions } = getEditorPlugin<CopilotPluginConfig>(editor, {\n key: KEYS.copilot,\n });\n\n const { getNextWord, suggestionText } = getOptions();\n\n if (!suggestionText?.length) {\n return false;\n }\n\n const { firstWord, remainingText } = getNextWord!({ text: suggestionText });\n\n api.copilot.setBlockSuggestion({\n text: remainingText,\n });\n\n withoutAbort(editor, () => {\n editor.tf.insertFragment(deserializeInlineMd(editor, firstWord));\n });\n};\n","import type { OverrideEditor, PlateEditor } from 'platejs/react';\n\nimport { serializeInlineMd } from '@platejs/markdown';\nimport {\n type Operation,\n type SlateEditor,\n type TRange,\n RangeApi,\n} from 'platejs';\n\nimport type { CopilotPluginConfig } from './CopilotPlugin';\n\nimport { withoutAbort } from './utils/withoutAbort';\n\ntype CopilotBatch = PlateEditor['history']['undos'][number] & {\n shouldAbort: boolean;\n};\n\nconst getPatchString = (editor: SlateEditor, operations: Operation[]) => {\n let string = '';\n\n for (const operation of operations) {\n if (operation.type === 'insert_node') {\n const node = operation.node;\n const text = serializeInlineMd(editor, { value: [node] });\n string += text;\n } else if (operation.type === 'insert_text') {\n string += operation.text;\n }\n }\n\n return string;\n};\n\nexport const withCopilot: OverrideEditor<CopilotPluginConfig> = ({\n api,\n editor,\n getOptions,\n setOption,\n tf: { apply, insertText, redo, setSelection, undo, writeHistory },\n}) => {\n let prevSelection: TRange | null = null;\n\n return {\n transforms: {\n apply(operation) {\n const { shouldAbort } = getOptions();\n\n if (shouldAbort) {\n api.copilot.reject();\n }\n\n apply(operation);\n },\n insertText(text, options) {\n const suggestionText = getOptions().suggestionText;\n\n // When using IME input, it's possible to enter two characters at once.\n if (suggestionText?.startsWith(text)) {\n withoutAbort(editor, () => {\n editor.tf.withoutMerging(() => {\n const newText = suggestionText?.slice(text.length);\n setOption('suggestionText', newText);\n insertText(text);\n });\n });\n\n return;\n }\n\n insertText(text, options);\n },\n\n redo() {\n if (!getOptions().suggestionText) return redo();\n\n const topRedo = editor.history.redos.at(-1) as CopilotBatch;\n const prevSuggestion = getOptions().suggestionText;\n\n if (topRedo && topRedo.shouldAbort === false && prevSuggestion) {\n withoutAbort(editor, () => {\n const shouldRemoveText = getPatchString(editor, topRedo.operations);\n\n const newText = prevSuggestion.slice(shouldRemoveText.length);\n setOption('suggestionText', newText);\n\n redo();\n });\n\n return;\n }\n\n return redo();\n },\n\n setSelection(props) {\n setSelection(props);\n\n if (\n editor.selection &&\n (!prevSelection ||\n !RangeApi.equals(prevSelection, editor.selection)) &&\n getOptions().autoTriggerQuery!({ editor }) &&\n editor.api.isFocused()\n ) {\n void api.copilot.triggerSuggestion();\n }\n\n prevSelection = editor.selection;\n },\n\n undo() {\n if (!getOptions().suggestionText) return undo();\n\n const lastUndos = editor.history.undos.at(-1) as CopilotBatch;\n const oldText = getOptions().suggestionText;\n\n if (lastUndos && lastUndos.shouldAbort === false && oldText) {\n withoutAbort(editor, () => {\n const shouldInsertText = getPatchString(\n editor,\n lastUndos.operations\n );\n\n const newText = shouldInsertText + oldText;\n setOption('suggestionText', newText);\n\n undo();\n });\n\n return;\n }\n\n return undo();\n },\n\n writeHistory(stacks, batch) {\n if (!getOptions().isLoading) {\n batch.shouldAbort = getOptions().shouldAbort;\n }\n\n return writeHistory(stacks, batch);\n },\n },\n };\n};\n","'use client';\n\nimport type React from 'react';\n\nimport type { DebouncedFunc } from 'lodash';\n\nimport { serializeMd } from '@platejs/markdown';\nimport debounce from 'lodash/debounce.js';\nimport {\n type OmitFirst,\n type PluginConfig,\n type TElement,\n bindFirst,\n KEYS,\n NodeApi,\n} from 'platejs';\nimport { type PlateEditor, createTPlatePlugin } from 'platejs/react';\n\nimport type { CompleteOptions } from './utils/callCompletionApi';\n\nimport { renderCopilotBelowNodes } from './renderCopilotBelowNodes';\nimport { acceptCopilot } from './transforms/acceptCopilot';\nimport { acceptCopilotNextWord } from './transforms/acceptCopilotNextWord';\nimport { type GetNextWord, getNextWord } from './utils/getNextWord';\nimport { triggerCopilotSuggestion } from './utils/triggerCopilotSuggestion';\nimport { withCopilot } from './withCopilot';\n\nexport type CopilotPluginConfig = PluginConfig<\n 'copilot',\n CompletionState & {\n /**\n * AI completion options. See:\n * {@link https://sdk.vercel.ai/docs/reference/ai-sdk-ui/use-completion#parameters | AI SDK UI useCompletion Parameters}\n */\n completeOptions?: Partial<CompleteOptions>;\n /**\n * Debounce delay for auto triggering AI completion.\n *\n * @default 0\n */\n debounceDelay?: number;\n /** Get the next word to be inserted. */\n getNextWord?: GetNextWord;\n /** Render the ghost text. */\n renderGhostText?: (() => React.ReactNode) | null;\n shouldAbort?: boolean;\n /** The node id where the suggestion is located. */\n suggestionNodeId?: string | null;\n /** The text of the suggestion. */\n suggestionText?: string | null;\n /**\n * Conditions to auto trigger copilot, used in addition to triggerQuery.\n * Disabling defaults to:\n *\n * - Block above is empty\n * - Block above ends with a space\n * - There is already a suggestion\n */\n autoTriggerQuery?: (options: { editor: PlateEditor }) => boolean;\n /**\n * Get the prompt for AI completion.\n *\n * @default serializeMdNodes(editor.api.block({ highest: true }))\n */\n getPrompt?: (options: { editor: PlateEditor }) => string;\n /**\n * Conditions to trigger copilot. Disabling defaults to:\n *\n * - Selection is expanded\n * - Selection is not at the end of block\n */\n triggerQuery?: (options: { editor: PlateEditor }) => boolean;\n // query?: QueryEditorOptions;\n },\n {\n copilot: {\n triggerSuggestion: OmitFirst<typeof triggerCopilotSuggestion>;\n // Function to abort the current API request and reject the completion state.\n reject: () => false | undefined;\n setBlockSuggestion: (options: { text: string; id?: string }) => void;\n // Function to abort the current API request.\n stop: () => void;\n };\n },\n {\n copilot: {\n accept: OmitFirst<typeof acceptCopilot>;\n acceptNextWord: OmitFirst<typeof acceptCopilotNextWord>;\n };\n },\n {\n isSuggested?: (id: string) => boolean;\n }\n>;\n\ntype CompletionState = {\n abortController?: AbortController | null;\n // The current text completion.\n completion?: string | null;\n // The error thrown during the completion process, if any.\n error?: Error | null;\n // Boolean flag indicating whether a fetch operation is currently in progress.\n isLoading?: boolean;\n};\n\nexport const CopilotPlugin = createTPlatePlugin<CopilotPluginConfig>({\n key: KEYS.copilot,\n handlers: {\n onBlur: ({ api }) => {\n api.copilot.reject();\n },\n onMouseDown: ({ api }) => {\n api.copilot.reject();\n },\n },\n options: {\n abortController: null,\n completeOptions: {},\n completion: '',\n debounceDelay: 0,\n error: null,\n getNextWord,\n isLoading: false,\n renderGhostText: null,\n shouldAbort: true,\n suggestionNodeId: null,\n suggestionText: null,\n autoTriggerQuery: ({ editor }) => {\n if (\n editor.getOptions<CopilotPluginConfig>({ key: KEYS.copilot })\n .suggestionText\n ) {\n return false;\n }\n\n const isEmpty = editor.api.isEmpty(editor.selection, { block: true });\n\n if (isEmpty) return false;\n\n const blockAbove = editor.api.block();\n\n if (!blockAbove) return false;\n\n const blockString = NodeApi.string(blockAbove[0]);\n\n return blockString.at(-1) === ' ';\n },\n getPrompt: ({ editor }) => {\n const contextEntry = editor.api.block({ highest: true });\n\n if (!contextEntry) return '';\n\n return serializeMd(editor, {\n value: [contextEntry[0] as TElement],\n });\n },\n triggerQuery: ({ editor }) => {\n if (editor.api.isExpanded()) return false;\n\n const isEnd = editor.api.isAt({ end: true });\n\n if (!isEnd) return false;\n\n return true;\n },\n },\n})\n .overrideEditor(withCopilot)\n .extendSelectors<CopilotPluginConfig['selectors']>(({ getOptions }) => ({\n isSuggested: (id) => getOptions().suggestionNodeId === id,\n }))\n .extendTransforms(({ editor }) => ({\n accept: bindFirst(acceptCopilot, editor),\n acceptNextWord: bindFirst(acceptCopilotNextWord, editor),\n }))\n .extendApi<Omit<CopilotPluginConfig['api']['copilot'], 'reject'>>(\n ({ api, editor, getOptions, setOption, setOptions }) => {\n const debounceDelay = getOptions().debounceDelay;\n\n let triggerSuggestion = bindFirst(triggerCopilotSuggestion, editor);\n\n if (debounceDelay) {\n triggerSuggestion = debounce(\n bindFirst(triggerCopilotSuggestion, editor),\n debounceDelay\n ) as any;\n }\n\n return {\n triggerSuggestion,\n setBlockSuggestion: ({ id = getOptions().suggestionNodeId, text }) => {\n if (!id) {\n id = editor.api.block()![0].id as string;\n }\n\n setOptions({\n suggestionNodeId: id,\n suggestionText: text,\n });\n },\n stop: () => {\n const { abortController } = getOptions();\n\n (api.copilot.triggerSuggestion as DebouncedFunc<any>)?.cancel();\n\n if (abortController) {\n abortController.abort();\n setOption('abortController', null);\n }\n },\n };\n }\n )\n .extendApi(({ api, getOptions, setOptions }) => ({\n reject: () => {\n if (!getOptions().suggestionText?.length) return false;\n\n api.copilot.stop();\n\n setOptions({\n completion: null,\n suggestionNodeId: null,\n suggestionText: null,\n });\n },\n }))\n .extend({\n render: {\n belowNodes: renderCopilotBelowNodes,\n },\n shortcuts: {\n accept: {\n keys: 'tab',\n },\n reject: {\n keys: 'escape',\n },\n },\n });\n"],"mappings":";;;;;;;;;;;;;;;AAQA,MAAaK,WAAWJ,cAAcE,aAAa;;;;ACLnD,SAASQ,mBAAmBC,KAAqB;AAC/C,KAAIA,OAAO,EAAG,QAAO;AACrB,KAAIA,OAAO,EAAG,QAAO;AACrB,KAAIA,OAAO,GAAI,QAAO;AACtB,KAAIA,OAAO,GAAI,QAAO;AAEtB,QAAO;;;AAIT,SAAgBC,qBAAqB,EACnCC,OACAC,YAIe;CACf,MAAM,CAACC,WAAWC,aAAaH;CAG/B,MAAMI,eAA+D,EAAE;CACvE,IAAII,WAAW;AAGf,MAAK,MAAM,CAACC,UAAUC,aAAad,QAAQe,MAAMT,UAAU,EAAE;EAC3D,MAAMU,cAAcJ,SAASK;EAE7B,MAAMC,eAAe,CAAC,GAAGX,WAAW,GAAGO,SAAS;AAChDN,eAAaW,KAAK;GAChBV,QAAQO;GACRN,MAAMQ;GACNP,MAAME,SAASF;GAChB,CAAC;AACFC,cAAYC,SAASF;;AAGvB,KAAI,CAACC,SAAU,QAAO;CAGtB,IAAIQ,aAAaR,SAASS,QAAQhB,SAAS;CAC3C,IAAIiB,WAAWF,cAAc,IAAIA,aAAaf,SAASY,SAAS;AAGhE,KAAIG,eAAe,IAAI;EACrB,MAAMG,UAAUtB,mBAAmBI,SAASY,OAAO;EACnD,IAAIO,YAAY;GAAE5B,UAAU6B,OAAOC;GAAmBC,KAAK;GAAIC,OAAO;GAAI;AAG1E,OAAK,IAAIC,IAAI,GAAGA,KAAKjB,SAASK,SAASZ,SAASY,QAAQY,IAEtD,MAAK,IAAIC,YAAY,CAACP,SAASO,aAAaP,SAASO,aAAa;GAChE,MAAM5B,MAAMG,SAASY,SAASa;AAC9B,OAAI5B,OAAO,KAAK2B,IAAI3B,MAAMU,SAASK,OAAQ;GAG3C,MAAMgB,OAAOrC,SADKgB,SAASoB,MAAMH,GAAGA,IAAI3B,IAAI,EACXG,SAAS;AAE1C,OAAI4B,QAAQV,WAAWU,OAAOT,UAAU5B,SACtC4B,aAAY;IAAE5B,UAAUqC;IAAMN,KAAKE,IAAI3B;IAAK0B,OAAOC;IAAG;;AAK5D,MAAIL,UAAUI,UAAU,IAAI;AAC1BR,gBAAaI,UAAUI;AACvBN,cAAWE,UAAUG;;;AAKzB,KAAIP,eAAe,GAEjB,MAAK,IAAIc,YAAY7B,SAASY,SAAS,GAAGiB,YAAY,GAAGA,aAAa;EACpE,MAAMC,SAAS9B,SAAS2B,MAAM,GAAGI,KAAKC,IAAI,GAAGH,UAAU,CAAC;EACxD,MAAMI,MAAM1B,SAASS,QAAQc,OAAO;AACpC,MAAIG,QAAQ,IAAI;AACdlB,gBAAakB;AACbhB,cAAWgB,MAAMJ;AACjB;;;AAKN,KAAId,eAAe,GAAI,QAAO;CAG9B,MAAMmB,aACJC,YACAC,QAAQ,UAC2B;AAEnC,MAAI,CAACA,OACH;QAAK,MAAMC,WAAWlC,aACpB,KAAIgC,eAAeE,QAAQjC,OACzB,QAAO;IACLA,QAAQ;IACRC,MAAMgC,QAAQhC;IACf;;AAMP,OAAK,MAAMgC,WAAWlC,cAAc;GAClC,MAAMmC,aAAaD,QAAQjC,SAASiC,QAAQ/B,KAAKM;AAEjD,OAAIuB,cAAcE,QAAQjC,UAAU+B,cAAcG,WAEhD,QAAO;IACLlC,QAFkB+B,aAAaE,QAAQjC;IAGvCC,MAAMgC,QAAQhC;IACf;;EAKL,MAAMmC,cAAcrC,aAAasC,GAAG,GAAG;AACvC,MAAI,CAACD,YACH,QAAO;GAAEpC,QAAQ;GAAGC,MAAMH;GAAW;AAEvC,SAAO;GACLE,QAAQoC,YAAYlC,KAAKM;GACzBP,MAAMmC,YAAYnC;GACnB;;AAMH,QAAO;EACLqC,QAJaR,UAAUnB,YAAY,MAAM;EAKzC4B,OAJYT,UAAUjB,UAAU,KAAK;EAKtC;;;;;AC1HH,MAAamC,oBACXC,QACAC,cACsB;CACtB,MAAM,EAAEC,SAASC,YAAYF;CAE7B,MAAMG,eAAeb,cAAcS,QAAQG,QAAQ;CAEnD,IAAIE;CAEJ,MAAMC,SAAkB,EAAE;AAC1BF,cAAaG,SAASC,MAAMC,UAAU;EACpC,IAAIC;AAEJ,MAAID,UAAU,GAAG;AACfJ,gBAAaL,OAAOW,IAAIH,KAAe;IAAEI,IAAIV;IAASW,IAAI,EAAA;IAAI,CAAC;AAC/DH,kBAAeL;SACV;AACL,OAAI,CAACA,WAAY;GAEjB,MAAM,CAACS,GAAGC,kBAAkBV;GAE5B,MAAMW,YAAY,CAACD,eAAe,KAAKN,MAAM;AAC7CC,kBAAeV,OAAOW,IAAIH,KAAKQ,UAAU;;AAG3C,MAAI,CAACN,aAAc;EAEnB,MAAMO,QAAQnB,qBAAqB;GACjCoB,OAAOR;GACPS,UAAUvB,QAAQwB,OAAOZ,KAAI;GAC9B,CAAC;AAEF,MAAI,CAACS,MAAO;AAEZX,SAAOe,KAAKJ,MAAM;GAClB;AAEF,KAAIX,OAAOgB,WAAW,EAAG;AAEzB,KAAIhB,OAAOgB,SAAS,GAAG;EACrB,MAAMC,aAAajB,OAAO;EAC1B,MAAMkB,WAAWlB,OAAOO,GAAG,GAAG;AAE9B,SAAO;GACLY,QAAQF,WAAWE;GACnBC,OAAOF,SAASE;GACjB;;AAGH,KAAIpB,OAAOgB,WAAW,EACpB,QAAOhB,OAAO;;;;;ACvDlB,MAAa0B,uBAAuBC,WAAwB;AAK1DC,CAJoBD,OAAOE,OAAOJ,iBAAiB,CAACK,WAAWC,MAAM,EACnEC,WAAW,MACZ,CAAC,CAEUC,SAAS,CAACC,oBAAgC;EACpD,MAAMC,iBAAiBR,OACpBE,OAAOJ,iBAAiB,CACxBK,WAAWK,eAAeD,eAAe;AAE5C,MAAI,CAACC,eAAgB;AAUrBb,mBAAiBK,QARG;GAClBU,WAAW,IAAIC,KAAKH,eAAeE,UAAU;GAC7CE,OAAOhB,iBAAiBY,eAAeK,GAAG;GAC1CC,cAAcN,eAAeK;GAC7BE,MAAMP,eAAeO;GACrBC,QAAQR,eAAeQ;GACxB,CAEoC;GACrC;AAEFhB,QAAOiB,GAAGC,WAAW,CAACrB,2BAA2B,CAAC,EAAE;EAClDsB,IAAI,EAAE;EACNC,MAAM;EACNC,QAAQC,MAAM,CAAC,CAACA,EAAEzB,2BAA2B;EAC9C,CAAC;;;;;AC5BJ,MAAakC,gBAAgBC,WAAwB;CACnD,MAAMC,OAAOD,OAAOE,UAAUL,cAAc,OAAO;AAEnD,KAAII,SAAS,UAAU;EACrB,MAAM,EAAEE,OAAOV,gBAAgBO,QAAQL,SAAS;EAChD,MAAMS,MAAMJ,OAAOK,OAA2B,EAAEC,KAAKf,KAAKgB,IAAI,CAAC;EAE/D,MAAMC,iBAAiBJ,IAAIK,OAAOC,KAAK;GAAEC,IAAI,EAAE;GAAEC,SAAS;GAAM,CAAC,CAAE;AAEnElB,cAAYM,cAAc;AACxBG,MAAGI,GAAGM,aAAa;AACnBb,UAAOc,cAAcjB,aAAa,CAACY,OAAOM,cAAc;IACxD;AAEFX,MAAIK,OAAOO,MAAM;AACjBhB,SAAOG,GAAGc,OAAO;EAEjB,MAAMC,aAAalB,OAAOI,IAAIe,IAAIX,eAAe;AAEjDR,SAAOG,GAAGiB,aAAa;GACrBC,QAAQH;GACRD,OAAOC;GACR,CAAC;;AAGJ,KAAIjB,SAAS,QAAQ;AACnBP,cAAYM,cAAc;AACxBF,uBAAoBE,OAAO;IAC3B;AAEFA,SAAOK,OAAOR,aAAa,CAACY,OAAOO,MAAM;;;;;;;AC5B7C,MAAaY,qBACXC,UAC6B;AAC7B,KAAIA,MAAMC,WAAW,EAAG,QAAO;CAE/B,MAAMC,QAAQF,MAAM;AAEpB,KAAIE,MAAMC,SAASV,KAAKS,MAAO,QAAO;CAEtC,MAAME,OAAOF,MAAMG;AAEnB,KAAID,KAAKH,WAAW,EAAG,QAAO;CAE9B,MAAMK,MAAMF,KAAK;AAEjB,KAAIE,IAAIH,SAASV,KAAKc,GAAI,QAAO;CAEjC,MAAMC,QAAQF,IAAID;AAElB,KAAIG,MAAMP,WAAW,EAAG,QAAO;AAI/B,QAFaO,MAAM,GAEPL,SAASV,KAAKiB;;;AAI5B,MAAaC,wBAAwBT,UAAuC;AAI1E,QAHYA,MAAMG,SAAS,GACVA,SAAS,GAEdA;;;;;ACfd,MAAa0B,sBAAsBC,QAAqBC,YAAoB;;AAE1ED,QACGE,OAAO,EAAEC,KAAKX,KAAKY,eAAe,CAAC,EAClCA,eAAeC,aAAa,YAAY;CAE5C,MAAM,EAAEC,cAAcN,OAAOO,WAAWZ,aAAa;AAIrD,KAAIW,UAAUE,SAAS,GAAG;EACxB,MAAMC,iBAAiBC,QAAkB;AACvCV,UAAOW,UAAUhB,cAAc,eAAee,IAAI;;AAGpD,MAAIV,OAAOY,UAAUjB,cAAc,cAAc,CAACa,WAAW,EAC3DC,eAAcH,UAAUO,KAAKC,SAASA,KAAKC,GAAa,CAAC;EAG3D,MAAMC,YAAYC,aAAajB,QAAQC,QAAQ;EAE/C,MAAMiB,eAAeC,MAAMC,KACzBpB,OAAOqB,IAAIC,MAAkB;GAC3BC,IAAI,EAAE;GACNC,QAAQC,MACNlC,WAAWmC,UAAUD,EAAE,IACvBzB,OAAOY,UAAUjB,cAAc,cAAc,CAACgC,SAASF,EAAEV,GAAE;GAC9D,CACH,CAAC;AAEDG,eAAaU,SAAS,CAACd,MAAMe,OAAOC,UAAU;GAC5C,MAAMC,WAAWf,UAAUc;AAG3B,OAAI,CAACC,SAAU;AAIf,OACED,UAAUZ,aAAaV,SAAS,KAChCQ,UAAUR,SAASU,aAAaV,QAChC;AACAR,WAAOgC,GAAGd,aAAaF,UAAUiB,MAAMH,MAAM,EAAE,EAC7CP,IAAIM,MACL,CAAC;AACF;;GAGF,MAAMK,cAAcpB;GACpB,MAAMqB,iBAAiBJ;GAEvB,MAAMK,eACJpD,sBAAsBgB,QAAQkC,YAAY,KAC1ClD,sBAAsBgB,QAAQmC,eAAe;GAE/C,MAAME,mBACHH,YAAYI,YAA4CC,SACxDJ,eAAeG,YAA4CC;AAE9D,OAAIH,gBAAgBC,oBAAoBvB,KAAKC,OAAOgB,SAAShB,GAC3D;AAGFf,UAAOgC,GAAGd,aAAaa,UAAU,EAC/BR,IAAIM,MACL,CAAC;IACF;AAEF7B,SACGE,OAAOrB,qBAAqB,CAC5B2D,eAAeC,IAAIzB,UAAUH,KAAKC,SAASA,KAAKC,GAAa,CAAC;AACjEN,gBAAcO,UAAUH,KAAKC,SAASA,KAAKC,GAAa,CAAC;QACpD;EACL,MAAMC,YAAYC,aAAajB,QAAQC,QAAQ;AAE/CD,SAAOgC,GAAGU,eAAe1B,UAAU;EAEnC,MAAMM,QAAQH,MAAMC,KAClBpB,OAAOqB,IAAIC,MAAM;GACfC,IAAI,EAAE;GACNoB,MAAM;GACNnB,QAAQC,MAAM/B,QAAQkD,OAAOnB,EAAE,IAAI,CAAC,CAACA,EAAE1C,2BAA2B;GACnE,CACH,CAAC;EAED,MAAM8D,QAAQ7C,OAAOqB,IAAIyB,WAAWxB,MAAM;AAE1CtB,SAAOgC,GAAGe,aAAaF,MAAO;AAE9B;;;AAIJ,MAAMG,aACJhC,WACAV,cAEAU,UAAUH,KAAKC,MAAMgB,UAAU;AAC7B,KAAI,CAACvC,WAAWmC,UAAUZ,KAAK,CAAE,QAAOA;CAExC,MAAMmC,eAAe3C,YAAYwB;AAEjC,QAAO;EACL,GAAGhB;EACH,GAAImC,gBAAgB,EAAElC,IAAItB,QAAO,EAAG;EACpCyD,UAAUpC,KAAKoC;EAChB;EACD;AAEJ,MAAaC,iBAAiBnC,cAC5BA,UAAUH,KAAKC,SAAS;AACtB,KAAIpB,QAAQkD,OAAO9B,KAAK,CACtB,QAAO;EACL,GAAGA;GACF/B,2BAA2B,GAAG;EAChC;AAEH,QAAO;EACL,GAAG+B;EACHoC,UAAUC,cAAcrC,KAAKoC,SAAS;GACrCnE,2BAA2B,GAAG;EAChC;EACD;AAEJ,MAAaqE,gCACX9B,UAEAA,MAAMT,KAAKC,SAAS;AAClB,KAAIpB,QAAQkD,OAAO9B,KAAK,EAAE;AACxB,MAAIA,KAAKtB,KAAK8C,eAAexB,KAAKtB,KAAK6D,SACrC,QAAO,EACLC,MAAMxC,KAAKwC,MACZ;AAGH,SAAOxC;;AAET,KAAIvB,WAAWmC,UAAUZ,KAAK,EAAE;AAC9B,MAAIA,KAAKtB,KAAK8C,aAAa;GACzB,MAAMiB,wBAA6B,EAAE;AAErCC,UAAOC,KAAK3C,KAAK,CAACc,SAASzB,QAAQ;AACjC,QAAIA,QAAQX,KAAK8C,cAAc,CAACnC,IAAIuD,WAAWlE,KAAK8C,WAAW,CAC7DiB,uBAAsBpD,OAAOW,KAAKX;KAEpC;AAEF,UAAO;IACL,GAAGoD;IACHL,UAAUE,6BAA6BtC,KAAKoC,SAAQ;IACrD;;AAGH,SAAO;GACL,GAAGpC;GACHoC,UAAUE,6BAA6BtC,KAAKoC,SAAQ;GACrD;;AAGH,QAAOpC;EACP;AAEJ,MAAMG,gBAAgBjB,QAAqB2D,cAAsB;CAI/D,IAAIrD,YAAY8C,6BAFKpD,OAAOY,UAAUjB,cAAc,YAAY,CAEN;;AAG1D,KAAIG,kBAAkBQ,UAAU,CAC9BA,aAAYT,qBAAaS,UAAU,GAAG;CAGxC,MAAMuD,UAAUb,UAAUpE,cAAcoB,QAAQ2D,UAAU,EAAErD,UAAU;AAQtE,QANkB6C,cAChBrE,kBAAkBkB,QAAQM,WAAWuD,SAAS,EAC5CC,aAAa,CAAC,MAAM,YAAW,EAChC,CACH,CAAC;;;;;;;;;;AC1LH,MAAaW,4BACXC,QACAC,eACG;CACH,MAAM,EAAEJ,SAASC,OAAOG;CAGxB,MAAMC,YAAYF,OAAOG,IAAIC,KAAK;EAChCC,IAAI,EAAE;EACNC,QAAQC,MAAMd,WAAWe,UAAUD,EAAE,IAAIA,EAAET,OAAOA;EACnD,CAAC;AAEF,KAAI,CAACI,WAAW;AACdO,UAAQC,KAAK,uBAAuBZ,GAAE,aAAc;AACpD;;CAGF,MAAM,CAACa,MAAMC,YAAYV;CAczB,MAAMgB,qBAAqBvB,cALTL,kBAAkBU,QANXN,6BAA6BiB,KAAKG,SAAS,EAGpDzB,cAAcW,QAAQH,QAAQ,EAGyB,EACrEoB,aAAa,CAAC,KAAI,EACnB,CAAC,CAGiD;AAGnDjB,QAAOmB,GAAGC,aAAaF,oBAAoB;EACzCb,IAAIO;EACJE,UAAU;EACX,CAAC;;;;;ACpDJ,SAAgBU,wBAAwBC,QAAqB;AAG3D,QAFiBA,OAAOE,WAAWJ,aAAa,CAACK,KAAKF,UAErCG,UAAUC,YAAYA,QAAQC,SAAS,YAAY;;AAGtE,SAAOC,0BAAA;CAAA,MAAAC,IAAAC,EAAA,EAAA;CACL,MAAAC,WAAiBb,gBAAgBC,cAAc,WAAW;CAC1D,MAAAK,OAAaN,gBAAgBC,cAAc,OAAO;AAElD,KAAIY,aAAa,UAAS;CAAS,IAAAC;AAAA,KAAAH,EAAA,OAAAL,KAAAF,UAAA;AAE5BU,OAAAR,KAAIF,UAAmBG,SAACQ,MAA0C;AAAAJ,IAAA,KAAAL,KAAAF;AAAAO,IAAA,KAAAG;OAAAA,MAAAH,EAAA;AAAA,QAAlEG;;AANF,SAAAC,MAAAP,SAAA;AAAA,QAMuCA,QAAOC,SAAU;;;;;ACP/D,MAAaY,uBAAuBC,WAAwB;AAK1DC,CAJoBD,OAAOE,OAAOJ,iBAAiB,CAACK,WAAWC,MAAM,EACnEC,WAAW,MACZ,CAAC,CAEUC,SAAS,CAACC,oBAAgC;EACpD,MAAMC,iBAAiBR,OACpBE,OAAOJ,iBAAiB,CACxBK,WAAWK,eAAeD,eAAe;AAE5C,MAAI,CAACC,eAAgB;AAUrBX,mBAAiBG,QARG;GAClBU,WAAW,IAAIC,KAAKH,eAAeE,UAAU;GAC7CE,OAAOjB,iBAAiBa,eAAeK,GAAG;GAC1CC,cAAcN,eAAeK;GAC7BE,MAAMP,eAAeO;GACrBC,QAAQR,eAAeQ;GACxB,CAEoC;GACrC;AAEFhB,QAAOiB,GAAGC,WAAW,CAACtB,2BAA2B,CAAC,EAAE;EAClDuB,IAAI,EAAE;EACNC,MAAM;EACNC,QAAQC,MAAM,CAAC,CAACA,EAAE1B,2BAA2B;EAC9C,CAAC;;;;;AC7BJ,MAAagC,eACXC,QACA,EAAEC,OAAO,SAA6B,EAAE,KACrC;CACH,MAAM,EAAEC,KAAKC,YAAYC,eAAeR,gBACtCI,QACA,EACEK,KAAKX,KAAKY,QAEd,CAAC;AAEDJ,KAAII,OAAOC,MAAM;CAEjB,MAAMC,OAAOL,YAAY,CAACK;AAE1B,KAAIA,KAAKC,YAAYD,KAAKC,SAASC,SAAS,EAC1CF,MAAKG,cAAc,EAAE,CAAC;AAGxBP,YAAW;EACTQ,aAAa,EAAE;EACfC,WAAW,EAAE;EACbC,MAAM;EACNC,UAAU;EACX,CAAC;AAEF,KAAId,KACFD,QAAOgB,cAAclB,SAAS,CAACmB,GAAGhB,MAAM;;;;;ACZ5C,MAAaiC,gBACXC,QACAC,OACA,EACEC,MACAC,SACAC,QACAC,UAAUC,kBAMR,EAAE,KACH;CACH,MAAM,EAAEC,YAAYC,cAAchB,gBAChCQ,QACA,EACES,KAAKtB,KAAKuB,QAEd,CAAC;CAED,MAAM,EAAEC,MAAMN,UAAUO,mBAAmBL,YAAY;CAEvD,MAAMF,WAAWC,iBAAiBM,kBAAkB;AAEpD,KAAI,CAACR,UAAUH,OAAOY,WAAW,EAC/B;AAEF,KAAI,CAACT,OACHA,UAASH;AAEX,KAAI,CAACC,KACHA,QAAOlB,YAAYgB,OAAO,GAAG,SAAS;AAExC,KAAIE,SAAS,SACXF,QAAOc,cAAchB,SAAS,CAACiB,GAAGC,MAAM;AAG1CR,WAAU,QAAQN,KAAK;AAEvBM,WAAU,YAAYH,SAAS;CAE/B,MAAMY,SAAkCjB,OACrCkB,OAAOjC,qBAAqB,CAC5BkC,eAAeC,UAAU;CAC5B,MAAMC,cAAcrB,OAAOsB,IAAIC,WAAWN,OAAO;CAEjD,MAAMO,aAAa3B,gBAAgBG,QAAQ,EACzCI,QACD,CAAC;CAEF,MAAMqB,YAAYR,OAAOJ,SAAS,IAAIQ,cAAcrB,OAAOyB;CAE3D,IAAIC;AAEJ,KAAIT,OAAOJ,SAAS,EAClBa,aAAYT,OAAOU,KAAKC,UAAUA,MAAM,GAAG;MACtC;EACL,MAAMC,kBAAkB7B,OAAOsB,IAAIL,OAAO,EAAEf,MAAM,WAAW,CAAC;AAE9D,MAAI2B,gBAAgBhB,SAAS,EAC3Ba,aAAYG,gBAAgBF,KAAKC,UAAUA,MAAM,GAAG;MAEpDF,aAAY1B,OAAOsB,IAAIQ,UAAsB;;AAIjDtB,WAAU,aAAakB,UAAU;AACjClB,WAAU,iBAAiBS,OAAOJ,SAAS,IAAI,OAAOb,OAAOyB,UAAU;CAEvE,MAAMM,MAIF;EACFC,UAAUhC,OAAOgC;EACjBP,WAAWA,aAAa;EACxBpB;EACD;AAED,CAAKM,KAAKsB,cACR,EACEC,MAAMV,YACP,EACD;EACEW,MAAM,EACJJ,KACD;EACD,GAAG5B;EAEP,CAAC;;;;;AC/FH,MAAa4C,yBAAyB,EACpCC,QACAC,QACAC,kBAKI;AACJ,KAAID,WAAW,OAAQ,QAAOV,UAAUS,OAAO;CAE/C,MAAM,CAACG,cAAcD;CACrB,MAAME,iBAAiBR,QAAQS,UAAUF,WAAW;AAEpD,KAAI,CAACC,eAAgB,QAAO;CAE5B,MAAME,aAAaV,QAAQW,aAAaJ,WAAW;CACnD,MAAMK,YAAYZ,QAAQW,aAAaH,eAAe,GAAG;CAEzD,MAAMK,uBAAuBC,SAAmB;AAC9C,MAAIb,QAAQc,OAAOD,KAAK,CACtB,QAAO;GAAE,GAAGF;GAAW,GAAGE;GAAM;AAElC,MAAIA,KAAKE,SACP,QAAO;GACL,GAAGF;GACHE,UAAUF,KAAKE,SAASC,IAAIJ,oBAAmB;GAChD;AAGH,SAAOC;;AAGT,QAAOV,OAAOa,KAAKC,OAAOC,UAAU;AAClC,MAAId,WAAW,YAAYc,QAAQ,EACjC,QAAOD;AAGT,SAAOL,oBAAoB;GACzB,GAAGK;GACH,GAAGR;GACJ,CAAC;GACF;;AAGJ,MAAaU,0BACXC,QACAC,cACA,EAAEjB,SAAS,aAAqD,EAAE,KAC/D;AACH,KAAI,CAACiB,gBAAgBA,aAAaC,IAAIC,SAAS,CAAE;CAEjD,MAAMC,mBAAmBJ,OAAOK,UAC9BjC,sBACA,kBACD;AAED4B,QAAOM,OAA2B,EAAEC,KAAK7B,KAAK8B,IAAI,CAAC,CAACC,OAAOC,MAAM;AAGjE,KAAI,CAACN,kBAAkB;EACrB,MAAMO,aAAaX,OAAOE,IAAIT,KAAK;GACjCI,OAAO;GACPe,MAAM;GACP,CAAC;AAEF,MACED,cACAX,OAAOE,IAAIW,WAAWF,WAAW,IAAI,EAAEG,UAAU,MAAM,CAAC,IACxD9B,WAAW,QACX;GACA,MAAM+B,oBAAkBjC,sBAAsB;IAC5CC,QAAQT,UAAU2B,aAAaN,SAAS;IACxCX;IACAC,aAAa0B;IACd,CAAC;AAEF,OAAI,CAACI,kBAAiB;;AAGtB,OACEJ,WAAW,GAAGK,SAAStC,KAAKuC,YAC5BhB,aAAaN,SAAS,GAAGqB,SAAStC,KAAKwC,aACvCjB,aAAaN,SAASwB,WAAW,EAEjCnB,QAAOoB,GAAGC,eAAeN,kBAAgB,GAAGpB,SAAS;OAErDK,QAAOoB,GAAGC,eAAeN,kBAAgB;AAG3Cf,UAAOoB,GAAGE,OAAO;AAEjB;;AAGFtB,SAAOoB,GAAGC,eAAepB,aAAaN,SAAS;AAC/CK,SAAOoB,GAAGE,OAAO;AAEjB;;CAIF,MAAMG,iBADoBzB,OAAOM,OAAOlC,qBAAqB,CAACoD,eACrBE,UAAU;AAEnD,KAAID,eAAeN,WAAW,EAAG;AAGjC,KAAInC,WAAW,UAAWA,WAAW,YAAYyC,eAAeN,SAAS,GAAI;AAC3EnB,SAAOoB,GAAGO,yBAAyB;AACjCtD,6BAA0B2B,OAAO;AAEjCA,UAAOoB,GAAGQ,mBAAmB;AAC3B5B,WACG6B,cAAczD,qBAAqB,CACnCoD,eAAeM,sBACdxD,UAAU2B,aAAaN,SAAS,EAChC,EACEoC,IAAIN,eAAe,GAAG,IAE1B,CAAC;KACH;IACF;AAEFzB,SAAOM,OAAOlC,qBAAqB,CAACoD,eAAeF,OAAO;AAE1D;;CAMF,MAAM,GAAGU,kBAAkBP,eAAe;CAC1C,MAAMV,kBAAkBjC,sBAAsB;EAC5CC,QAAQT,UAAU2B,aAAaN,SAAS;EACxCX;EACAC,aAAawC,eAAe;EAC7B,CAAC;AAEF,KAAI,CAACV,gBAAiB;AAEtBf,QAAOoB,GAAGO,yBAAyB;AACjCtD,4BAA0B2B,OAAO;AAEjCA,SAAOoB,GAAGQ,mBAAmB;AAC3B5B,UACG6B,cAAczD,qBAAqB,CACnCoD,eAAeM,sBAAsBf,iBAAiB,EACrDgB,IAAIC,gBACL,CAAC;IACJ;GACF;AAEFhC,QAAOM,OAAOlC,qBAAqB,CAACoD,eAAeF,OAAO;;;;;ACvJ5D,MAAa0B,qBACXC,QACAC,cACA,EAAEC,SAAS,aAAqD,EAAE,KAC/D;CACH,MAAM,EAAEC,aAAaH,OAAOI,WAAWR,aAAa;AAEpD,KAAIO,aAAa,WACf,QAAOE,oBAAoBL,QAAQC,cAAc,EAAEC,QAAQ,CAAC;CAE9D,MAAMI,iBAA0CN,OAC7CO,OAAOtB,qBAAqB,CAC5BuB,eAAeC,UAAU;CAE5B,MAAMC,cAAcV,OAAOI,WAAWnB,qBAAqB,CAACyB;AAE5DV,QAAOW,cAAcjB,SAAS,CAACkB,GAAGC,MAAM;CAExC,MAAMC,wBACJd,OAAOW,cAAc1B,qBAAqB,CAACuB,eACxCM;AAEL,KAAI,CAACJ,eAAeA,YAAYK,SAAS,EAAG;CAE5C,MAAMC,YAAYV,eAAeW,GAAG,GAAG;AAEvC,KAAI,CAACD,UAAW;CAEhB,MAAME,WAAW7B,QAAQ8B,KAAKH,UAAU,GAAG;AAI3CF,uBAFcR,eAAee,KAAKC,UAAUA,MAAM,GAAG,EAExB;EAC3BL,IAAIC;EACJK,wBAAwB;AACtB9B,eAAYO,cAAc;AACxBH,wBAAoBG,OAAO;KAC3B;;EAEL,CAAC;AAEFA,QAAOO,OAAOX,aAAa,CAAC4B,OAAOC,KAAK,EAAEC,OAAO,OAAO,CAAC;;AAG3D,MAAarB,uBACXL,QACAC,cACA,EAAEC,SAAS,aAAqD,EAAE,KAC/D;AACH,KAAI,CAACD,gBAAgBA,aAAa0B,IAAIC,SAAS,CAAE;CAEjD,MAAMC,mBAAmB7B,OAAO8B,UAC9B7C,sBACA,kBACD;AAEDe,QAAOO,OAA2B,EAAEwB,KAAK3C,KAAKwB,IAAI,CAAC,CAACY,OAAOC,MAAM;CAEjE,MAAMX,wBACJd,OAAOW,cAAc1B,qBAAqB,CAACuB,eACxCM;AAEL,KAAIe,kBAAkB;EACpB,MAAMvB,iBAAiBN,OACpBO,OAAOtB,qBAAqB,CAC5BuB,eAAeC,UAAU;EAE5B,MAAMC,cAAcV,OAAOI,WAAWnB,qBAAqB,CAACyB;AAE5D,MAAI,CAACA,eAAeA,YAAYK,SAAS,EAAG;EAE5C,MAAMC,YAAYV,eAAeW,GAAG,GAAG;AAEvC,MAAI,CAACD,UAAW;EAEhB,MAAME,WAAW7B,QAAQ8B,KAAKH,UAAU,GAAG;AAE3C,MAAId,WAAW,QAAQ;AACrBY,yBAAsB5B,UAAUe,aAAa+B,SAAS,EAAE,EACtDf,IAAIC,UACL,CAAC;AAEF;;EAGF,MAAMe,kBAAkBnC,sBAAsB;GAC5CoC,QAAQhD,UAAUe,aAAa+B,SAAS;GACxC9B;GACAiC,aAAanB;GACd,CAAC;AAEF,MAAI,CAACiB,gBAAiB;AAEtBnB,wBAAsBmB,iBAAiB,EACrChB,IAAIC,UACL,CAAC;QACG;EACL,MAAM,GAAGkB,OAAO9C,SAAS+C,MAAMrC,OAAOsC,UAAW;EACjD,MAAMC,UAAU,CAACH,IAAII,KAAK,GAAG;EAC7B,MAAMC,eAAezC,OAAO2B,IAAIe,KAAK;GACnCzB,IAAIsB;GACJjB,OAAO;GACPqB,MAAM;GACP,CAAC;AAEF,MAAI,CAACF,aAAc;AACnB,MAAIvC,WAAW,QAAQ;AACrBY,yBAAsB5B,UAAUe,aAAa+B,SAAS,EAAE,EACtDf,IAAI5B,QAAQ8B,KAAKoB,QAAO,EACzB,CAAC;AAEF;;EAGF,MAAMN,kBAAkBnC,sBAAsB;GAC5CoC,QAAQhD,UAAUe,aAAa+B,SAAS;GACxC9B;GACAiC,aAAaM;GACd,CAAC;AAEF,MAAI,CAACR,gBAAiB;AAEtBnB,wBAAsBmB,iBAAiB,EACrChB,IAAI5B,QAAQ8B,KAAKoB,QAAO,EACzB,CAAC;;;;;;ACtIN,MAAaU,sBACXC,QACAC,YACG;AACHD,QAAOE,GAAGC,oBAAoB;AAC5BH,SAAOE,GAAGE,YAAY;GACpBC,IAAI,EAAE;GACNC,QAAQC,MACNX,WAAWY,UAAUD,EAAE,IACvBA,EAAEE,SAASZ,cAAcG,QAAQF,KAAKY,OAAO;GAC/C,GAAGT;GACJ,CAAC;GACF;;;;;ACdJ,MAAagB,cAAkD,EAC7DC,KACAC,QACAC,YACAC,IAAI,EAAEC,YAAYC,iBAClBC,WACI;CACJ,MAAMH,KAAKF,OAAOM,cAAcX,SAAS;CAEzC,MAAMY,kBAAkBC,SAAiB;EACvC,MAAM,EAAEC,YAAYR,YAAY;AAEhC,MAAIQ,mBAAmBC,OACrB,QAAOD,QAAQE,KAAKH,KAAK;AAE3B,MAAII,MAAMC,QAAQJ,QAAQ,CACxB,QAAOA,QAAQK,SAASN,KAAK;AAG/B,SAAOA,SAASC;;AAGlB,QAAO,EACLM,YAAY;EACVZ,WAAWK,MAAMQ,SAAS;GACxB,MAAM,EAAEC,4BAA4BC,iBAAiBjB,YAAY;GAEjE,MAAMkB,WAAW;AACf,QACE,CAACnB,OAAOoB,aACR,CAACb,eAAeC,KAAK,IACpBU,gBAAgB,CAACA,aAAalB,OAAQ,CAEvC;IAIF,MAAMqB,eAAerB,OAAOD,IAAIuB,OAC9BtB,OAAOD,IAAIwB,MAAM,UAAUvB,OAAOoB,UACpC,CAAC;AAKD,QAAI,CAFFH,4BAA4BN,KAAKU,aAAa,CAEf;IAEjC,MAAMI,YAAYzB,OAAOD,IAAI2B,MAAM,EAAEC,SAAS,MAAM,CAAC;AAErD,QAAI,CAACF,aAAa,CAACzB,OAAOD,IAAI6B,QAAQH,UAAU,GAAG,CAAE;AAErD1B,QAAI8B,OAAOC,MAAM;AAEjB,WAAO;;AAGT,OAAIX,IAAI,CAAE;AAEV,UAAOhB,WAAWK,MAAMQ,QAAQ;;EAElCZ,cAAc2B,OAAO;GACnB,MAAM,CAACC,MAAMC,QAAQF;AAErB,OAAIC,KAAKtC,KAAKwC,OAAO,CAACjC,YAAY,CAACkC,MAAM;AACvCjC,OAAGgC,GAAGE,YAAY,EAAEC,IAAIJ,MAAM,CAAC;AAE/B;;AAGF,OACExC,WAAW6C,UAAUN,KAAK,IAC1BA,KAAK3B,SAASA,QACd,CAACJ,YAAY,CAACkC,MACd;AACAnC,WAAOM,cAAcT,aAAa,CAACgC,OAAOU,aAAa,EAAEF,IAAIJ,MAAM,CAAC;AAEpE;;AAGF,UAAO7B,cAAc2B,MAAM;;EAE/B,EACD;;;;;ACJH,MAAamE,eAAe3C,mBAAuC;CACjE4C,KAAK7C,KAAK4B;CACVkB,cAAc,CAAC,KAAK;CACpBX,MAAM,EACJY,WAAW,MACZ;CACDf,SAAS;EACPjB,cAAc;EACdC,YAAY;EACZC,UAAU;EACVC,aAAa,EAAE;EACfC,UAAU;EACVC,MAAM,EAAE4B,UAAU,EAAA,EAAI;EACtB3B,WAAW,EAAE;EACbC,eAAe;EACfC,yBAAyB;EACzBC,MAAM;EACNC,MAAM;EACNC,WAAW;EACXC,UAAU;EACVsB,SAAS;EACTC,4BAA4B;EAC9B;CACD,CAAC,CACCC,eAAetC,WAAW,CAC1BuC,WAKE,EAAEE,QAAQC,WAAWC,YAAYC,WAAWC,YAAY;CACzD7B,OAAOhC,UAAUc,aAAa2C,OAAO;CACrCxB,QAAQjC,UAAUe,cAAc0C,OAAO;CACvCnB,OAAOH,UAAU,EAAE,KAAK;EACtB,MAAM,EAAEI,SAAS,OAAOV,YAAY,OAAO,GAAGiC,SAAS3B;AAEvD,MAAII,OACF,QAAOkB,OAAOM,IAAIzB,KAAK;GACrB0B,IAAI,EAAE;GACNC,QAAQC,MAAMjE,WAAWiD,UAAUgB,EAAE,IAAIA,EAAEL,SAASA;GACpD,GAAGC;GACJ,CAAC;AAGJ,MAAIjC,WAAW;AACb,OAAI,CAAC6B,UAAU,YAAY,CAAE;GAE7B,MAAMS,OAAOT,UAAU,aAAa;AACpC,OAAI,CAACS,KAAM;AAEX,UAAOV,OAAOM,IAAIzB,KAAK;IACrB0B,IAAIG;IACJxC,MAAM;IACNyC,SAAS;IACTH,QAAQI,MAAM,CAAC,CAACA,EAAEnE,cAAcuD,QAAQtD,KAAKmE,GAAG;IAChD,GAAGR;IACJ,CAAC;;AAGJ,SAAOL,OAAOM,IAAIzB,KAAK;GACrB2B,QAAQC,MAAMA,EAAEhE,cAAcuD,QAAQtD,KAAKmE,GAAG;GAC9C,GAAGR;GACJ,CAAC;;CAEJtB,cAAc;EACZ,MAAM,EAAEjB,MAAMC,WAAWC,kBAAkBkC,YAAY;AAEvDF,SAAOc,cAAc9D,SAAS,CAAC6D,GAAGjC,MAAM;AAExC,MAAIZ,cACFgC,QAAOe,GAAGC,aAAahD,cAAc;MAErCgC,QACGiB,OAAOnF,qBAAqB,CAC5BoF,eAAeC,IAAIpD,UAAUqD,KAAKvC,SAASA,KAAKwC,GAAa,CAAC;EAGnE,MAAMC,SAAStB,OACZiB,OAAOnF,qBAAqB,CAC5BoF,eAAeK,UAAU;EAE5B,MAAMC,YACJF,OAAOG,SAAS,IAAIzB,OAAOM,IAAIoB,WAAWJ,OAAO,GAAGtB,OAAOwB;EAE7D,MAAMG,MAAM;GACVC,UAAU5B,OAAO4B;GACjBJ,WAAWA,aAAa;GACxBnD,UAAU4B,UAAU,WAAU;GAC/B;AAED,EAAKnC,KAAK+D,aAAa,EACrBC,MAAM,EACJH,KACF,EACD,CAAC;;CAEJ1C,YAAY;AACVkB,YAAU,aAAa,MAAM;AAC7BD,cAAY,CAACpC,KAAKmB,QAAQ;;CAE7B,EAAE,CACFa,WAAW,EAAEQ,KAAKN,QAAQE,YAAYC,WAAWY,UAAU;CAC1DtC,OAAO,EACLE,QAAQ,MACRC,OAAO,SAIL,EAAE,KAAK;AACT0B,MAAIhC,OAAOC,MAAM,EAAEK,MAAM,CAAC;AAE1BuB,YAAU,QAAQ,MAAM;AAExB,MAAIxB,MACF,KAAIqB,OAAOC,UAAUnE,sBAAsB,kBAAkB,CAC3DkE,QAAOiB,OAAOnF,qBAAqB,CAACoF,eAAevC,OAAO;MAE1DqB,QAAOe,GAAGpC,OAAO;EAIrB,MAAMoD,YAAY/B,OAAOgC,QAAQC,MAAM1B,GAAG,GAAG;AAE7C,MAAIwB,WAAWlB,GACbkB,WAAUlB,KAAKqB;AAGjBnB,KAAGzC,OAAOe,cAAc;;CAE1BL,YAAY;AACVsB,MAAIhC,OAAOC,OAAO;AAElB4B,YAAU,YAAY,KAAK;AAE3BD,cAAY,CAACpC,KAAKqE,cAAc,EAAE,CAAC;AAEnChC,YAAU,QAAQ,KAAK;;CAE1B,EAAE,CACFiC,kBAAkB,EAAEpC,cAAc;CACjCd,QAAQ3C,UAAUW,cAAc8C,OAAO;CACvCb,aAAa5C,UAAUY,mBAAmB6C,OAAO;CACjDX,cAAc9C,UAAUU,oBAAoB+C,OAAO;CACnDZ,kBAAkB7C,UAAUa,wBAAwB4C,OAAM;CAC3D,EAAE;;;;;;;;;;ACrNL,MAAa4C,mBACXC,QACAC,SACA,EAAEC,WAAiC,EAAE,KAClC;CACH,MAAM,EAAEC,cAAcN,gBAAgBC,aAAa;CAEnD,MAAMM,WAAWX,cACT;AAOJ,SANeO,OACZM,OAAOV,eAAe,CACtBW,SAASC,YAAYP,SAAS;GAC7BQ,SAAS;GACTP;GACD,CAAC;IAIN,CAACD,QACH,CAAC;AAEDD,QAAOI,WAAWA;AAElBZ,iBAAgB;AACdW,YAAU,YAAYH,OAAO;IAC5B,CAACA,QAAQG,UAAU,CAAC;AAEvB,QAAOC;;;;;AC/BT,MAAaa,gBAAgB,EAC3BC,SACAC,eASI;CACJ,MAAM,EAAEM,WAAWX,gBACjB,EAAEY,KAAKb,KAAKc,QAAQ,EACpB,OACD;CACD,MAAMC,YAAYH,WAAW,eAAeA,WAAW;CAEvD,MAAMD,UAAUR,yBAAyB,EAAEa,MAAMC,MAC9CC,SAASA,KAAKC,SAAS,OACzB,EAAET;CAEH,MAAMU,kBAAkBtB,OAAe,GAAG;CAC1C,MAAMuB,mBAAmBvB,OAAOiB,UAAU;AAE1ClB,iBAAgB;AACd,MAAI,CAACkB,UACHK,iBAAgBE,UAAU;AAE5B,MAAID,iBAAiBC,WAAW,CAACP,UAC/BT,YAAW,EAAEK,SAASA,WAAW,IAAI,CAAC;AAGxCU,mBAAiBC,UAAUP;IAE1B,CAACA,UAAU,CAAC;AAEflB,iBAAgB;AACd,MAAI,CAACc,QACH;EAGF,MAAMJ,QAAQI,QAAQY,MAAMH,gBAAgBE,QAAQE,OAAO;EAE3D,MAAMf,QAAiB,EAAE;AAEzB,MAAIF,OAAO;GACT,MAAMC,UAAUY,gBAAgBE,YAAY;AAE5Cb,SAAMgB,KAAK,EAAEf,MAAMH,OAAO,CAAC;AAC3BF,WAAQ;IACNE;IACAC;IACAC;IACAC,MAAMC;IACP,CAAC;;AAGJS,kBAAgBE,UAAUX;IAEzB,CAACA,QAAQ,CAAC;;;;;ACnDf,MAAa6B,iBAAiB,EAC5BN,sBACAE,cACAE,cACAC,sBAC0B;CAC1B,MAAM,EAAEE,WAAWZ,gBAAgBE,aAAa;CAChD,MAAMM,OAAOP,gBAAgBC,cAAc,OAAO;AAElDL,iBAAgB;AACdU,iBAAeC,KAAK;AAEpB,MAAIA,MAAM;AACR,OAAIH,sBAAsB;IACxB,MAAMQ,oBACJD,OAAOE,OAAOf,qBAAqB,CAACgB;AAMtC,QALyBH,OAAOK,UAC9BlB,sBACA,kBACD,EAEqB;AACpBM,0BAAqBQ,kBAAkBK,UAAU,CAAC;AAElD;;;AAGJ,OAAIT,gBAAgBG,OAAOO,IAAIC,aAAa,EAAE;AAC5CX,kBAAc;AAEd;;AAEF,OAAIC,mBAAmBE,OAAOO,IAAIE,YAAY,EAAE;AAC9CX,qBAAiB;AAEjB;;;IAIH,CAACF,KAAK,CAAC;;;;;ACvDZ,MAAaiB,6BACXC,QACAC,MACAC,YACGF,OAAOG,OAAOL,eAAe,CAACM,SAASC,kBAAkBJ,MAAMC,QAAQ;;;;ACR5E,MAAaI,mBACXC,OACA,EACEC,YAAY,YAGV,EAAE,KACH;CACH,MAAMC,MAAMD,cAAc,UAAUD,MAAMG,SAAS,GAAGH,MAAMI,WAAW;AAEvE,KAAIH,cAAc,QAChB,QAAOD,MAAMK,MAAMH,IAAII,OAAO;AAEhC,QAAON,MAAMK,MAAM,GAAGL,MAAMM,SAASJ,IAAII,OAAO;;AAGlD,SAAgBC,oBAAoBL,KAAa;CAC/C,MAAMM,UAAUN,IAAIO,MAAM;CAE1B,MAAMC,sBAAsBF,QAAQG,WAAW,MAAM;CACrD,MAAMC,oBAAoBJ,QAAQK,SAAS,MAAM;AAEjD,QAAOH,uBAAuBE;;AAGhC,SAAgBE,eAAeZ,KAAa;CAC1C,MAAMM,UAAUN,IAAIO,MAAM;CAE1B,MAAMM,iBAAiBP,QAAQG,WAAW,KAAK;CAC/C,MAAMK,eAAeR,QAAQK,SAAS,KAAK;AAE3C,QAAOE,kBAAkBC;;;;;AC7B3B,MAAaE,eAAeC,SAAiB;CAC3C,IAAIC,MAAMD;AAGV,KACEA,KAAKE,WAAW,KAAK,IACrB,CAACF,KAAKE,WAAW,OAAO,IACxB,CAACJ,eAAeE,KAAK,CAErBC,OAAMD,KAAKG,QAAQ,MAAMC,OAAOC,GAAG,OAAO;AAG5C,QAAOJ;;;;;ACXT,MAAaO,eAAeC,QAAqBC,SAA6B;AAC5E,KAAIA,KAAKC,iBAAiBD,KAAKE,WAAW;EACxC,MAAMC,eAAeJ,OAAOK,IAAIC,SAAS,EACvCC,IAAIP,OAAOQ,WAAWC,OACvB,CAAC,GAAG;AAGL,MAAIL,cAAcF,iBAAiBE,cAAcD,UAC/C,QAAOF;AAET,MAAIA,KAAKE,cAAc,EAAG,QAAOF;AAEjC,SAAO;GACL,GAAGA;GACHS,mBAAmBT,KAAKE;GACzB;;AAGH,QAAOF;;;;;ACjBT,MAAMe,kBAAkB;AAExB,MAAaC,cACXC,QACAC,OACAC,UACG;AACH,KACED,MAAME,SAASH,OAAOI,QAAQP,KAAKQ,EAAE,IACrCH,MAAMC,SAASH,OAAOI,QAAQP,KAAKQ,EAAE,CAErC,QAAOJ,MAAME,SAASD,MAAMC;AAE9B,KAAIP,UAAUK,MAAMH,iBAAiB,IAAIF,UAAUM,MAAMJ,iBAAiB,CACxE,QAAOG,MAAMH,qBAAqBI,MAAMJ;AAG1C,QAAOG,MAAME,SAASD,MAAMC;;;;;ACb9B,MAAaQ,kBACXC,QACAC,OACAC,YAEAD,MAAME,KAAKC,SAAqB;AAC9B,KAAIR,WAAWS,UAAUD,KAAK,CAC5B,QAAO;EACL,GAAGN,YAAYE,QAAQI,KAAK;EAC5B,GAAGF,QAAQI;EACXC,UAAUR,eAAeC,QAAQI,KAAKG,UAAUL,QAAO;EACxD;AAEH,QAAO;EACL,GAAGA,QAAQM;EACX,GAAGJ;EACHK,MAAML,KAAKK;EACZ;EACD;;;;ACjBJ,MAAMW,kBAAkB;AAExB,MAAaC,uBACXC,QACAC,MACAC,YACG;CACH,MAAMC,QAAQN,YAAYI,KAAK;CAE/B,MAAMG,QAAQC,wBAAwBL,QAAQG,MAAM;AAEpD,KAAIG,MAAMC,QAAQH,MAAM,CAAE,QAAOA;CAEjC,IAAII,SAAqB,EAAE;AAE3BA,UAASR,OAAOS,OAAOnB,eAAe,CAACoB,SAASC,YAAYR,OAAO;EACjE,GAAGD;EACHU,yBAAyB;EAC1B,CAAC;CAEF,MAAMC,cAAcjB,gBAAgBK,KAAK;CAEzC,MAAMa,YAAYN,OAAOO,GAAG,GAAG;CAE/B,MAAMC,aAAaH,gBAAgB;CACnC,MAAMI,iBACJrB,gBAAgBK,MAAM,EAAEiB,WAAW,QAAQ,CAAC,KAAK;CAEnD,MAAMC,qBACJL,WAAWM,SAAS,gBAAgBN,WAAWM,SAAS;CAE1D,IAAIC,SAASb;;;;;AAOb,KACEM,aACA,CAACK,sBACDN,YAAYS,SAAS,KACrB,CAACN,YACD;EACA,MAAMO,WAAW,CACf,EACEC,MAAMX,aACP,CACF;EAED,MAAMY,YAAYX,UAAUY,SAASX,GAAG,GAAG;;AAG3C,MACEU,aACA/B,QAAQiC,OAAOF,UAAU,IACzBG,OAAOC,KAAKJ,UAAU,CAACH,WAAW,GAClC;AACAR,aAAUY,SAASI,KAAK;GAExB,MAAMP,aAAW,CACf,EACEC,MAAMC,UAAUD,OAAOX,aACxB,CACF;AAEDC,aAAUY,SAASK,KAAK,GAAGR,WAAS;QAEpCT,WAAUY,SAASK,KAAK,GAAGR,SAAS;AAGtCF,WAAS,CAAC,GAAGb,OAAOwB,MAAM,GAAG,GAAG,EAAElB,UAAU;;AAG9C,KAAIE,cAAc,CAACG,mBACjBE,QAAOU,KAAK;EACVL,UAAU,CAAC,EAAEF,MAAM,IAAI,CAAC;EACxBJ,MAAM3B,KAAKwC;EACZ,CAAC;AAGJ,KAAIhB,kBAAkB,CAACE,mBACrBE,QAAOa,QAAQ;EACbR,UAAU,CAAC,EAAEF,MAAM,IAAI,CAAC;EACxBJ,MAAM3B,KAAKwC;EACZ,CAAC;AAGJ,QAAOZ;;AAGT,MAAMhB,2BAA2BL,QAAqBG,UAAkB;CACtE,MAAMgC,UAAUnC,OAAOoC,UAAUzC,cAAc,WAAW;AAE1D,KAAIwC,SAAS;AAGX,MAFiBhC,MAAMmC,SAAS,KAAKH,QAAO,GAAI,EAElC;AACZnC,UAAOuC,UAAU5C,cAAc,YAAY,KAAK;AAChD,UAAO;;AAET,SAAO,CACL;GACE+B,UAAU,CACR,EACEF,MAAMrB,OACP,CACF;GACDiB,MAAM5B,cAAcQ,QAAQP,KAAKwC,EAAC;GACnC,CACF;;CAEH,MAAMO,aAAa1C,gBAAgB2C,KAAKtC,MAAM,GAAG;AAGjD,KAAIA,MAAMuC,WAAW,IAAIF,aAAa,CACpCxC,QAAOuC,UAAU5C,cAAc,YAAY6C,cAAc,KAAK;;;;;AC1GlE,MAAMc,kBACJC,QACAC,UACiD;CACjD,MAAME,cAAc,IAAIC,IAAI;EAC1BV,KAAKW;EACLX,KAAKY;EACLZ,KAAKa;EACLb,KAAKc;EACLd,KAAKe;EACLf,KAAKgB;EACN,CAAC;CACF,MAAMC,YAAYV,MAAMW,GAAG,GAAG;AAE9B,KACED,aACAR,YAAYU,IACTpB,aAAaO,QAAQW,UAAUG,KAAe,IAAIH,UAAUG,KAC9D,IACDtB,WAAWuB,UAAUJ,UAAU,EAC/B;EACA,MAAMK,eAAeL,UAAUM,SAASL,GAAG,GAAG;AAE9C,MAAIjB,QAAQuB,OAAOF,aAAa,EAAE;GAChC,MAAMd,cAAcN,gBAAgBoB,cAAcG,KAAe;GAGjE,MAAMC,cAAc,CAClB,GAAGT,UAAUM,SAASI,MAAM,GAAG,GAAG,EAClC,EAAEF,MAAMH,aAAaG,KAAKG,SAAQ,EAAG,CACtC;GAED,MAAMC,eAAe;IACnB,GAAGZ;IACHM,UAAUG;IACX;AAED,UAAO;IACLlB;IACAD,OAAO,CAAC,GAAGA,MAAMoB,MAAM,GAAG,GAAG,EAAEE,aAAY;IAC5C;;;AAIL,QAAO;EAAErB,aAAa;EAAID;EAAO;;AAGnC,MAAauB,qBACXxB,QACAyB,SACAC,UACG;CACH,MAAM,EAAEzB,OAAO0B,cAAc,GAAGC,gBAAgBH;CAChD,MAAM,EAAExB,UAAUF,eAAeC,QAAQ2B,gBAAgB3B,OAAOiB,SAAS;CAEzE,IAAIY,SAAS;AAEbA,UAAS7B,OAAO8B,OAAOxC,eAAe,CAACyC,SAASC,UAAU;EACxD/B;EACA,GAAG2B;EACJ,CAAC;CAEF,MAAMK,eAAerC,gBAAgB8B,MAAM;AAE3C,KAAI7B,oBAAoBgC,OAAO,IAAI,CAACH,MAAMQ,SAAS,MAAM,CACvDL,UAASA,OAAOP,SAAS,CAACD,MAAM,GAAG,GAAG,GAAGY;AAG3C,KAAInC,eAAe+B,OAAO,IAAI,CAACH,MAAMQ,SAAS,KAAK,CACjDL,UAASA,OAAOP,SAAS,CAACD,MAAM,GAAG,GAAG,GAAGY;AAI3CJ,UAASA,OAAOM,QAAQ,WAAW,IAAI;AACvCN,UAASA,OAAOM,QAAQ,aAAa,IAAI;AACzCN,UAASA,OAAOM,QAAQ,WAAW,GAAG;AAItC,KAAIF,iBAAiB,OACnBJ,UAASA,OAAOP,SAAS,GAAGW;AAI9B,KAAIP,MAAMQ,SAAS,OAAO,EACxB;MAAIL,WAAW,KAEbA,UAAS;WACAA,OAAOK,SAAS,OAAO,CAEhCL,UAASA,OAAOR,MAAM,GAAG,GAAG;;AAOhCQ,UAASA,OAAOM,QAAQ,sCAAsC,KAAK;AAEnE,QAAON;;;;;AC/FT,MAAMuB,eAAeC,MAAYC,WAAmB;CAClD,IAAIC,SAASF;AAEb,MAAK,IAAIG,IAAI,GAAGA,IAAIF,QAAQE,IAC1BD,UAASb,QAAQe,KAAKF,OAAO;AAE/B,QAAOA;;;AAIT,SAAgBG,kBACdC,QACAC,OACAC,UAAmC,EAAE,EACrC;CACA,MAAM,EAAEC,cAAcC,eAAeJ,OAAOK,WAAWrB,aAAa;AAEpE,KAAIoB,eAAe,MAAM;EACvB,MAAME,SAASpB,oBAAoBc,QAAQC,MAAM;EACjD,MAAMP,OAAOa,oBAAoBP,OAAO;EACxC,MAAMQ,aAAaR,OAAOS,IAAIC,KAAKhB,KAAK,CAAE;EAE1C,MAAMiB,wBACJ7B,QAAQ8B,OAAOJ,WAAW,CAACb,WAAW,KACtCa,WAAWK,SAASjC,cAAcoB,QAAQnB,KAAKiC,EAAE;AAGnD,MAAIH,sBACFX,QAAOe,GAAGC,YAAY,EAAEC,IAAIvB,MAAM,CAAC;AAGrC,MAAIY,OAAOX,SAAS,GAAG;AACrBK,UAAOe,GAAGG,YAAY7B,eAAeW,QAAQ,CAACM,OAAO,GAAG,EAAEJ,QAAQ,EAAE;IAClEe,IAAIvB;IACJyB,WAAW,CAACR;IACZS,QAAQ;IACT,CAAC;AAEFpB,UAAOqB,UAAUrC,cAAc,cAAcuB,oBAAoBP,OAAO,CAAC;AACzEA,UAAOqB,UAAUrC,cAAc,gBAAgBiB,MAAM;AAErD,OAAIK,OAAOX,SAAS,GAAG;IACrB,MAAM2B,aAAahB,OAAOiB,MAAM,EAAE;IAElC,MAAMC,WAAWjB,oBAAoBP,OAAO;AAE5CA,WAAOe,GAAGG,YAAY7B,eAAeW,QAAQsB,YAAYpB,QAAQ,EAAE;KACjEe,IAAIO;KACJL,WAAW;KACXC,QAAQ;KACT,CAAC;IAEF,MAAMK,YAAYzB,OAAOS,IAAIC,KAC3BjB,YAAY+B,UAAUF,WAAW3B,OACnC,CAAC;AAEDK,WAAOqB,UAAUrC,cAAc,cAAcyC,UAAU,GAAG;IAE1D,MAAMC,kBAAkBvC,kBACtBa,QACA,EACE2B,OAAO,CAACF,UAAU,GAAE,EACrB,EACDxB,MACD;AAEDD,WAAOqB,UAAUrC,cAAc,gBAAgB0C,gBAAgB;;;QAG9D;EACL,MAAME,kBAAkBzB,eAAeF;EACvC,MAAM4B,aAAa3C,oBAAoBc,QAAQ4B,gBAAgB;AAc/D,MAAIC,WAAWlC,WAAW,EACxB,QAAOmC,QAAQC,KACb,uBAAuBC,KAAKC,UAAUL,gBAAgB,GACvD;AAGH,MAAIC,WAAWlC,WAAW,GAAG;GAC3B,MAAMuC,eAAelC,OAAOS,IAAIC,KAAKN,WAAW,CAAE;AAGlD,OAAIhB,WAAWY,QAAQkC,cAAcL,WAAW,GAAG,EAAE;IACnD,MAAMM,aAAalD,0BAA0Be,QAAeC,MAAM;AAGlED,WAAOe,GAAGG,YAAY7B,eAAeW,QAAQmC,YAAYjC,QAAQ,EAAE;KACjEe,IAAIjB,OAAOS,IAAI2B,IAAIhC,WAAW;KAC9BgB,QAAQ;KACT,CAAC;IAGF,MAAMkB,kBAAkBnD,kBACtBa,QACA,EACE2B,OAAO,CAJU3B,OAAOS,IAAIC,KAAKN,WAAW,CAIvB,GAAE,EACxB,EACDwB,gBACD;IAED,MAAMW,YAAYzD,QAAQ8B,OAAOiB,WAAW,GAAG;AAG/C,QACES,oBAAoBV,mBACpBW,cAAcD,gBAEdtC,QAAOqB,UAAUrC,cAAc,gBAAgB4C,gBAAgB;SAC1D;AACL5B,YAAOe,GAAGyB,aACRnD,eAAeW,QAAQ,CAAC6B,WAAW,GAAG,EAAE3B,QAAQ,EAChD;MACEe,IAAIb;MACJgB,QAAQ;MAEZ,CAAC;KAED,MAAMkB,oBAAkBnD,kBACtBa,QACA,EACE2B,OAAO,CAACE,WAAW,GAAE,EACtB,EACDD,gBACD;AAED5B,YAAOqB,UACLrC,cACA,gBAEA6C,WAAW,GAAGhB,SAASjC,cAAcoB,QAAQnB,KAAK4D,UAAU,IAC1DZ,WAAW,GAAGhB,SAASjC,cAAcoB,QAAQnB,KAAK6D,MAAM,IACxDb,WAAW,GAAGhB,SAASjC,cAAcoB,QAAQnB,KAAK8D,SAAS,GACzDf,kBACAU,kBACL;;UAEE;IACL,MAAMA,kBAAkBnD,kBACtBa,QACA,EACE2B,OAAO,CAACE,WAAW,GAAE,EACtB,EACDD,gBACD;AAED5B,WAAOe,GAAGyB,aACRnD,eAAeW,QAAQ,CAAC6B,WAAW,GAAG,EAAE3B,QAAQ,EAChD;KACEe,IAAIb;KACJgB,QAAQ;KAEZ,CAAC;AAEDpB,WAAOqB,UAAUrC,cAAc,gBAAgBsD,gBAAgB;;SAE5D;AACLtC,UAAOe,GAAGyB,aAAanD,eAAeW,QAAQ,CAAC6B,WAAW,GAAG,EAAE3B,QAAQ,EAAE;IACvEe,IAAIb;IACJgB,QAAQ;IACT,CAAC;AAEF,OAAIS,WAAWlC,SAAS,GAAG;IACzB,MAAMiD,kBAAkBnD,YAAYW,YAAYyB,WAAWlC,SAAS,EAAE;AAEtEK,WAAOe,GAAGG,YACR7B,eAAeW,QAAQ6B,WAAWN,MAAM,EAAE,EAAErB,QAAQ,EACpD;KACEe,IAAIlC,QAAQe,KAAKM,WAAW;KAC5BgB,QAAQ;KAEZ,CAAC;AAEDpB,WAAOqB,UAAUrC,cAAc,cAAc4D,gBAAgB;IAE7D,MAAMC,WAAW7C,OAAOS,IAAIC,KAAKkC,gBAAgB,CAAE;IAEnD,MAAMN,kBAAkBnD,kBACtBa,QACA,EACE2B,OAAO,CAACkB,SAAQ,EACjB,EACDjB,gBACD;AAED5B,WAAOqB,UAAUrC,cAAc,gBAAgBsD,gBAAgB;;;;;AAMvE,MAAa/B,uBAAuBP,WAAwB;CAC1D,MAAM8C,yBAAyB9C,aAA0C;EACvE,MAAM+C,aAAa/C,SAChBgD,OAAOhE,aAAa,CACpBiE,OAAOvC,KAAK,EAAEwC,QAAQ,MAAM,CAAC;AAEhC,MAAIH,WACF,QAAOhE,QAAQoE,SAASJ,WAAW,GAAG;;CAI1C,MAAMK,gBAAgBpD,aACpBA,SAAOqD,WAAWC,MAAM5D,KAAK6B,MAAM,GAAG,EAAE;CAE1C,MAAM7B,OAAOoD,sBAAsB9C,OAAO,IAAIoD,aAAapD,OAAO,IAAI,CAAC,EAAE;CAEzE,MAAMuD,QAAQvD,OAAOS,IAAIC,KAAKhB,KAAK;AAGnC,KACE6D,UACCA,MAAM,GAAG1C,SAASjC,cAAcoB,QAAQnB,KAAK2E,YAAY,IACxDD,MAAM,GAAG1C,SAASjC,cAAcoB,QAAQnB,KAAK6D,MAAM,EAErD,QAAO1C,OAAOS,IAAIgD,OAAO,GAAG,MAAM/D;AAGpC,QAAOA;;;;;ACpPT,MAAaqE,2BAA2B,EACtCC,aACiD;CAKjD,MAAM,EAAEG,iBAAiBC,cAJTP,gBAAqCG,QAAQ,EAC3DE,KAAKP,KAAKM,SACX,CAAC,CAE6CI,YAAY;AAE3D,KAAI,CAACD,UAAW;AAEhB,SAAQ,EAAEE,eACR,0DACGA,UAED,oCAAC,gBAAS,CAEb;;;;;ACnBH,MAAaM,iBAAiBC,WAAwB;CACpD,MAAM,EAAEC,mBAAmBD,OAAOE,WAAgC,EAChEC,KAAKN,KAAKO,SACX,CAAC;AAEF,KAAI,CAACH,gBAAgBI,OAAQ,QAAO;AAEpCL,QAAOM,GAAGC,eAAeX,oBAAoBI,QAAQC,eAAe,CAAC;;;;;ACbvE,MAAMO,yBAAyBC;AAyB/B,eAAsB6B,kBAAkB,EACtC1B,MAAM,mBACNC,MACAE,aACAN,iBAAQD,kBAAkB,EAC1BU,SACAP,QACAS,2BAA2B,IAC3BG,sBAAsB,IACtBE,iBAAiB,IACjBG,mBAAmB,IACnBE,SACAC,UACAC,cAC2B;AAC3B,KAAI;AACFJ,aAAW,KAAK;AAChBH,WAAS,KAAK;EAEd,MAAMJ,kBAAkB,IAAIC,iBAAiB;AAC7CF,qBAAmBC,gBAAgB;AAGnCE,gBAAc,GAAG;EAEjB,MAAMgB,MAAM,MAAM9B,QAAMG,KAAK;GAC3BC,MAAM2B,KAAKC,UAAU;IACnB9B;IACA,GAAGE;IACJ,CAAC;GACFE;GACAG,SAAS;IACP,gBAAgB;IAChB,GAAGA;IACJ;GACDwB,QAAQ;GACRC,QAAQtB,gBAAgBsB;GACzB,CAAC,CAACC,OAAOlB,UAAU;AAClB,SAAMA;IACN;AAEF,MAAIM,WACF,OAAMA,WAAWO,IAAI;AAEvB,MAAI,CAACA,IAAIM,GACP,OAAM,IAAIlB,MACP,MAAMY,IAAIO,MAAM,IAAK,qCACvB;AAEH,MAAI,CAACP,IAAI1B,KACP,OAAM,IAAIc,MAAM,8BAA8B;EAGhD,MAAM,EAAEmB,SAAS,MAAMP,IAAIQ,MAAM;AAEjC,MAAI,CAACD,KACH,OAAM,IAAInB,MAAM,8CAA8C;AAGhEJ,gBAAcuB,KAAK;AAEnB,MAAIf,SACFA,UAASpB,QAAQmC,KAAK;AAGxB1B,qBAAmB,KAAK;AAExB,SAAO0B;UACApB,OAAO;AAEd,MAAKA,MAAcsB,SAAS,cAAc;AACxC5B,sBAAmB,KAAK;AAExB,UAAO;;AAET,MAAIM,iBAAiBC,SAASG,QAC5BA,SAAQJ,MAAM;AAGhBD,WAASC,MAAe;WAChB;AACRE,aAAW,MAAM;;;;;;ACtGrB,MAAM0B,gBAAgB;AACtB,MAAMC,eACJ;AACF,MAAMC,gBACJ;AACF,MAAMC,mBACJ;AAEF,MAAaC,eAA4B,EAAEP,WAAW;AACpD,KAAI,CAACA,KAAM,QAAO;EAAEC,WAAW;EAAIC,eAAe;EAAI;CAGtD,MAAMM,gBAAgBL,cAAcM,KAAKT,KAAK;AAE9C,KAAI,CAACQ,cAAe,QAAO;EAAEP,WAAW;EAAIC,eAAe;EAAI;CAE/D,MAAMQ,oBAAoBF,cAAc;CAWxC,MAAMG,YAAYP,aAAaQ,KAAKF,kBAAkB;CAEtD,IAAIT;CACJ,IAAIC;AAEJ,KAAIS,WAAW;EAEb,MAAME,QAAQR,cAAcI,KAAKT,KAAK;AAEtC,MAAIa,OAAO;GACT,MAAM,GAAGC,SAAS,IAAIC,OAAO,IAAIC,cAAc,MAAMH;AACrDZ,eAAYa,SAASC,OAAOC;AAC5Bd,mBAAgBF,KAAKiB,MAAMhB,UAAUiB,OAAO;SACvC;AACLjB,eAAY;AACZC,mBAAgBF;;QAEb;EAEL,MAAMa,QAAQP,iBAAiBG,KAAKT,KAAK;AAEzC,MAAIa,OAAO;AACTZ,eAAYY,MAAM;AAClBX,mBAAgBF,KAAKiB,MAAMhB,UAAUiB,OAAO;SACvC;AACLjB,eAAYD;AACZE,mBAAgB;;;AAIpB,QAAO;EAAED;EAAWC;EAAe;;;;;ACvDrC,MAAasB,2BAA2B,OAAOC,WAAwB;CACrE,MAAM,EAAEC,KAAKC,YAAYC,cAAcP,gBACrCI,QACA,EACEI,KAAKV,KAAKW,SAEd,CAAC;CAED,MAAM,EAAEC,iBAAiBC,WAAWC,WAAWC,iBAAiBP,YAAY;AAE5E,KAAIM,aAAaR,OAAOE,WAAW,EAAEE,KAAKV,KAAKgB,QAAQ,CAAC,CAACC,MAAMH,UAC7D,QAAO;AAET,KAAI,CAACC,aAAc,EAAET,QAAQ,CAAC,CAAE,QAAO;CAIvC,MAAMY,SAASL,UAAW,EAAEP,QAAQ,CAAC;AAErC,KAAIY,OAAOC,WAAW,EAAG,QAAO;AAEhCZ,KAAII,QAAQS,MAAM;AAElB,OAAMhB,kBAAkB;EACtBc;EACAG,WAAWC,GAAGC,eAAe;AAC3BhB,OAAII,QAAQa,mBAAmB,EAAEC,MAAMF,YAAY,CAAC;;EAEtD,GAAGX;EACHc,qBAAqBC,eACnBlB,UAAU,mBAAmBkB,WAAW;EAC1CC,gBAAgBL,eAAed,UAAU,cAAcc,WAAW;EAClEM,WAAWC,UAAUrB,UAAU,SAASqB,MAAM;EAC9CC,aAAaC,YAAYvB,UAAU,aAAauB,QAAQ;EACxDC,UAAUH,UAAU;AAClBrB,aAAU,SAASqB,MAAM;AACzBlB,oBAAiBqB,UAAUH,MAAM;;EAEpC,CAAC;;;;;ACzCJ,MAAaM,gBAAgBC,QAAqBC,OAAmB;AACnED,QAAOE,UAAUJ,eAAe,eAAe,MAAM;AACrDG,KAAI;AACJD,QAAOE,UAAUJ,eAAe,eAAe,KAAK;;;;;ACCtD,MAAaW,yBAAyBC,WAAwB;CAC5D,MAAM,EAAEC,KAAKC,eAAeN,gBAAqCI,QAAQ,EACvEG,KAAKT,KAAKU,SACX,CAAC;CAEF,MAAM,EAAEC,4BAAaC,mBAAmBJ,YAAY;AAEpD,KAAI,CAACI,gBAAgBC,OACnB,QAAO;CAGT,MAAM,EAAEC,WAAWC,kBAAkBJ,cAAa,EAAEK,MAAMJ,gBAAgB,CAAC;AAE3EL,KAAIG,QAAQO,mBAAmB,EAC7BD,MAAMD,eACP,CAAC;AAEFX,cAAaE,cAAc;AACzBA,SAAOY,GAAGC,eAAepB,oBAAoBO,QAAQQ,UAAU,CAAC;GAChE;;;;;ACTJ,MAAMiB,kBAAkBC,QAAqBC,eAA4B;CACvE,IAAIC,SAAS;AAEb,MAAK,MAAMC,aAAaF,WACtB,KAAIE,UAAUC,SAAS,eAAe;EACpC,MAAMC,OAAOF,UAAUE;EACvB,MAAMC,OAAOhB,kBAAkBU,QAAQ,EAAEO,OAAO,CAACF,KAAI,EAAG,CAAC;AACzDH,YAAUI;YACDH,UAAUC,SAAS,cAC5BF,WAAUC,UAAUG;AAIxB,QAAOJ;;AAGT,MAAaM,eAAoD,EAC/DC,KACAT,QACAU,YACAC,WACAC,IAAI,EAAEC,OAAOC,YAAYC,MAAMC,cAAcC,MAAMC,qBAC/C;CACJ,IAAIC,gBAA+B;AAEnC,QAAO,EACLC,YAAY;EACVP,MAAMV,WAAW;GACf,MAAM,EAAEL,gBAAgBY,YAAY;AAEpC,OAAIZ,YACFW,KAAIY,QAAQC,QAAQ;AAGtBT,SAAMV,UAAU;;EAElBW,WAAWR,MAAMiB,SAAS;GACxB,MAAMC,iBAAiBd,YAAY,CAACc;AAGpC,OAAIA,gBAAgBC,WAAWnB,KAAK,EAAE;AACpCV,iBAAaI,cAAc;AACzBA,YAAOY,GAAGc,qBAAqB;MAC7B,MAAMC,UAAUH,gBAAgBI,MAAMtB,KAAKuB,OAAO;AAClDlB,gBAAU,kBAAkBgB,QAAQ;AACpCb,iBAAWR,KAAK;OAChB;MACF;AAEF;;AAGFQ,cAAWR,MAAMiB,QAAQ;;EAG3BR,OAAO;AACL,OAAI,CAACL,YAAY,CAACc,eAAgB,QAAOT,MAAM;GAE/C,MAAMe,UAAU9B,OAAO+B,QAAQC,MAAMC,GAAG,GAAG;GAC3C,MAAMC,iBAAiBxB,YAAY,CAACc;AAEpC,OAAIM,WAAWA,QAAQhC,gBAAgB,SAASoC,gBAAgB;AAC9DtC,iBAAaI,cAAc;KACzB,MAAMmC,mBAAmBpC,eAAeC,QAAQ8B,QAAQ7B,WAAW;AAGnEU,eAAU,kBADMuB,eAAeN,MAAMO,iBAAiBN,OAAO,CACzB;AAEpCd,WAAM;MACN;AAEF;;AAGF,UAAOA,MAAM;;EAGfC,aAAaoB,OAAO;AAClBpB,gBAAaoB,MAAM;AAEnB,OACEpC,OAAOqC,cACN,CAAClB,iBACA,CAACzB,SAAS4C,OAAOnB,eAAenB,OAAOqC,UAAU,KACnD3B,YAAY,CAAC6B,iBAAkB,EAAEvC,QAAQ,CAAC,IAC1CA,OAAOS,IAAI+B,WAAW,CAEtB,CAAK/B,IAAIY,QAAQoB,mBAAmB;AAGtCtB,mBAAgBnB,OAAOqC;;EAGzBpB,OAAO;AACL,OAAI,CAACP,YAAY,CAACc,eAAgB,QAAOP,MAAM;GAE/C,MAAMyB,YAAY1C,OAAO+B,QAAQY,MAAMV,GAAG,GAAG;GAC7C,MAAMW,UAAUlC,YAAY,CAACc;AAE7B,OAAIkB,aAAaA,UAAU5C,gBAAgB,SAAS8C,SAAS;AAC3DhD,iBAAaI,cAAc;AAOzBW,eAAU,kBANeZ,eACvBC,QACA0C,UAAUzC,WACX,GAEkC2C,QACC;AAEpC3B,WAAM;MACN;AAEF;;AAGF,UAAOA,MAAM;;EAGfC,aAAa4B,QAAQC,OAAO;AAC1B,OAAI,CAACrC,YAAY,CAACsC,UAChBD,OAAMjD,cAAcY,YAAY,CAACZ;AAGnC,UAAOoB,aAAa4B,QAAQC,MAAM;;EAEtC,EACD;;;;;ACvCH,MAAaqD,gBAAgBxC,mBAAwC;CACnEyC,KAAK5C,KAAK2B;CACVkB,UAAU;EACRC,SAAS,EAAEC,UAAU;AACnBA,OAAIpB,QAAQE,QAAQ;;EAEtBmB,cAAc,EAAED,UAAU;AACxBA,OAAIpB,QAAQE,QAAQ;;EAEvB;CACDN,SAAS;EACPc,iBAAiB;EACjBvB,iBAAiB,EAAE;EACnByB,YAAY;EACZvB,eAAe;EACfwB,OAAO;EACP/B;EACAiC,WAAW;EACXzB,iBAAiB;EACjBE,aAAa;EACbC,kBAAkB;EAClBC,gBAAgB;EAChBC,mBAAmB,EAAEE,aAAa;AAChC,OACEA,OAAOyB,WAAgC,EAAEL,KAAK5C,KAAK2B,SAAS,CAAC,CAC1DN,eAEH,QAAO;AAKT,OAFgBG,OAAOuB,IAAIG,QAAQ1B,OAAO2B,WAAW,EAAEC,OAAO,MAAM,CAAC,CAExD,QAAO;GAEpB,MAAMC,aAAa7B,OAAOuB,IAAIK,OAAO;AAErC,OAAI,CAACC,WAAY,QAAO;AAIxB,UAFoBpD,QAAQsD,OAAOF,WAAW,GAAG,CAE9BG,GAAG,GAAG,KAAK;;EAEhC/B,YAAY,EAAED,aAAa;GACzB,MAAMiC,eAAejC,OAAOuB,IAAIK,MAAM,EAAEM,SAAS,MAAM,CAAC;AAExD,OAAI,CAACD,aAAc,QAAO;AAE1B,UAAO/D,YAAY8B,QAAQ,EACzBmC,OAAO,CAACF,aAAa,GAAc,EACpC,CAAC;;EAEJ/B,eAAe,EAAEF,aAAa;AAC5B,OAAIA,OAAOuB,IAAIa,YAAY,CAAE,QAAO;AAIpC,OAAI,CAFUpC,OAAOuB,IAAIe,KAAK,EAAEC,KAAK,MAAM,CAAC,CAEhC,QAAO;AAEnB,UAAO;;EAEX;CACD,CAAC,CACCC,eAAerD,YAAY,CAC3BsD,iBAAmD,EAAEhB,kBAAkB,EACtEb,cAAcJ,OAAOiB,YAAY,CAAC7B,qBAAqBY,IACxD,EAAE,CACFkC,kBAAkB,EAAE1C,cAAc;CACjCU,QAAQnC,UAAUO,eAAekB,OAAO;CACxCW,gBAAgBpC,UAAUQ,uBAAuBiB,OAAM;CACxD,EAAE,CACF2C,WACE,EAAEpB,KAAKvB,QAAQyB,YAAYoB,WAAWC,iBAAiB;CACtD,MAAMtD,gBAAgBiC,YAAY,CAACjC;CAEnC,IAAIY,oBAAoB7B,UAAUW,0BAA0Bc,OAAO;AAEnE,KAAIR,cACFY,qBAAoBjC,SAClBI,UAAUW,0BAA0Bc,OAAO,EAC3CR,cACD;AAGH,QAAO;EACLY;EACAE,qBAAqB,EAAEE,KAAKiB,YAAY,CAAC7B,kBAAkBW,WAAW;AACpE,OAAI,CAACC,GACHA,MAAKR,OAAOuB,IAAIK,OAAO,CAAE,GAAGpB;AAG9BsC,cAAW;IACTlD,kBAAkBY;IAClBX,gBAAgBU;IACjB,CAAC;;EAEJE,YAAY;GACV,MAAM,EAAEI,oBAAoBY,YAAY;AAExC,GAACF,IAAIpB,QAAQC,mBAA0C2C,QAAQ;AAE/D,OAAIlC,iBAAiB;AACnBA,oBAAgBmC,OAAO;AACvBH,cAAU,mBAAmB,KAAK;;;EAGvC;EAEJ,CACAF,WAAW,EAAEpB,KAAKE,YAAYqB,kBAAkB,EAC/CzC,cAAc;AACZ,KAAI,CAACoB,YAAY,CAAC5B,gBAAgBoD,OAAQ,QAAO;AAEjD1B,KAAIpB,QAAQM,MAAM;AAElBqC,YAAW;EACT/B,YAAY;EACZnB,kBAAkB;EAClBC,gBAAgB;EACjB,CAAC;GAEL,EAAE,CACFqD,OAAO;CACNC,QAAQ,EACNC,YAAYvE,yBACb;CACDwE,WAAW;EACT3C,QAAQ,EACN4C,MAAM,OACP;EACDjD,QAAQ,EACNiD,MAAM,UACR;EACF;CACD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@lofcz/platejs-ai",
3
+ "version": "52.3.2",
4
+ "description": "Text AI plugin for Plate",
5
+ "keywords": [
6
+ "plate",
7
+ "plugin",
8
+ "slate"
9
+ ],
10
+ "homepage": "https://platejs.org",
11
+ "bugs": {
12
+ "url": "https://github.com/udecode/plate/issues"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/lofcz/plate.git",
17
+ "directory": "packages/ai"
18
+ },
19
+ "license": "MIT",
20
+ "sideEffects": false,
21
+ "exports": {
22
+ ".": "./dist/index.js",
23
+ "./react": "./dist/react/index.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "files": [
29
+ "dist/**/*"
30
+ ],
31
+ "dependencies": {
32
+ "fastest-levenshtein": "1.0.16",
33
+ "lodash": "^4.17.21",
34
+ "react-compiler-runtime": "^1.0.0",
35
+ "@platejs/markdown": "npm:@lofcz/platejs-markdown@52.3.5",
36
+ "@platejs/table": "npm:@lofcz/platejs-table@52.0.11",
37
+ "@platejs/suggestion": "npm:@lofcz/platejs-suggestion@52.0.11",
38
+ "@platejs/selection": "npm:@lofcz/platejs-selection@52.0.16"
39
+ },
40
+ "devDependencies": {
41
+ "@ai-sdk/react": "^3.0.0",
42
+ "ai": "^6.0.0",
43
+ "@plate/scripts": "1.0.0"
44
+ },
45
+ "peerDependencies": {
46
+ "platejs": ">=52.0.15",
47
+ "react": ">=18.0.0",
48
+ "react-dom": ">=18.0.0"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "type": "module",
54
+ "module": "./dist/index.js",
55
+ "scripts": {
56
+ "brl": "plate-pkg p:brl",
57
+ "build": "plate-pkg p:build",
58
+ "build:watch": "plate-pkg p:build:watch",
59
+ "clean": "plate-pkg p:clean",
60
+ "lint": "plate-pkg p:lint",
61
+ "lint:fix": "plate-pkg p:lint:fix",
62
+ "test": "plate-pkg p:test",
63
+ "test:watch": "plate-pkg p:test:watch",
64
+ "typecheck": "plate-pkg p:typecheck"
65
+ }
66
+ }