diff --git a/src/components/WikilinkChatInput.test.tsx b/src/components/WikilinkChatInput.test.tsx
index 1980a263..b31f2404 100644
--- a/src/components/WikilinkChatInput.test.tsx
+++ b/src/components/WikilinkChatInput.test.tsx
@@ -549,6 +549,7 @@ describe('WikilinkChatInput', () => {
it('treats missing inputType as a non-insert beforeinput event', () => {
expect(() => isInsertBeforeInput({} as InputEvent)).not.toThrow()
expect(isInsertBeforeInput({} as InputEvent)).toBe(false)
+ expect(isInsertBeforeInput({ inputType: 42 })).toBe(false)
expect(isInsertBeforeInput({ inputType: 'insertFromPaste' } as InputEvent)).toBe(true)
})
@@ -567,6 +568,26 @@ describe('WikilinkChatInput', () => {
expect(editor.textContent).toContain('still works')
})
+ it('ignores beforeinput events with non-string inputType instead of calling startsWith', () => {
+ render()
+
+ const editor = screen.getByTestId('agent-input')
+ const startsWith = vi.fn(() => true)
+ const beforeInputEvent = new Event('beforeinput', {
+ bubbles: true,
+ cancelable: true,
+ })
+ Object.defineProperty(beforeInputEvent, 'inputType', {
+ value: { startsWith },
+ })
+
+ expect(() => fireEvent(editor, beforeInputEvent)).not.toThrow()
+ expect(startsWith).not.toHaveBeenCalled()
+
+ updateEditorText('still works')
+ expect(editor.textContent).toContain('still works')
+ })
+
it('recovers if unsupported media lands in the editor DOM', async () => {
const onUnsupportedPaste = vi.fn()
render()
diff --git a/src/components/inlineWikilinkBeforeInput.ts b/src/components/inlineWikilinkBeforeInput.ts
index a9a6d39c..9c834287 100644
--- a/src/components/inlineWikilinkBeforeInput.ts
+++ b/src/components/inlineWikilinkBeforeInput.ts
@@ -1,11 +1,26 @@
-export function isInsertBeforeInput(nativeEvent: Pick) {
- return typeof nativeEvent.inputType === 'string'
- && nativeEvent.inputType.startsWith('insert')
+type BeforeInputLike = {
+ inputType?: unknown
+}
+
+type PlainTextBeforeInputLike = BeforeInputLike & {
+ data?: unknown
+ isComposing?: unknown
+}
+
+type PlainTextBeforeInput = PlainTextBeforeInputLike & {
+ data: string
+ inputType: 'insertText'
+ isComposing?: false
+}
+
+export function isInsertBeforeInput(nativeEvent: BeforeInputLike) {
+ const { inputType } = nativeEvent
+ return typeof inputType === 'string' && inputType.startsWith('insert')
}
export function isPlainTextBeforeInput(
- nativeEvent: Pick,
-): nativeEvent is Pick & { data: string } {
+ nativeEvent: PlainTextBeforeInputLike,
+): nativeEvent is PlainTextBeforeInput {
return nativeEvent.inputType === 'insertText'
&& !nativeEvent.isComposing
&& typeof nativeEvent.data === 'string'