Remove Matrix Widget API connection and logging
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 20s

This commit is contained in:
2026-01-19 23:35:12 +01:00
parent 5dac0b4c30
commit 5c6a8c9b84
4 changed files with 27 additions and 209 deletions

26
package-lock.json generated
View File

@@ -13,7 +13,6 @@
"express": "^5.2.1",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.562.0",
"matrix-widget-api": "^1.16.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
@@ -1425,12 +1424,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/events": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.3.tgz",
"integrity": "sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==",
"license": "MIT"
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -2547,15 +2540,6 @@
"node": ">= 0.6"
}
},
"node_modules/events": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
"license": "MIT",
"engines": {
"node": ">=0.8.x"
}
},
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
@@ -3232,16 +3216,6 @@
"node": ">= 0.4"
}
},
"node_modules/matrix-widget-api": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.16.0.tgz",
"integrity": "sha512-OCsCzEN54jWamvWkBa7PqcKdlOhLA+nJbUyqsATHvzb4/NMcjdUZWSDurZxyNE5eYlNwxClA6Hw20mzJEKJbvg==",
"license": "Apache-2.0",
"dependencies": {
"@types/events": "^3.0.0",
"events": "^3.2.0"
}
},
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",

View File

@@ -16,7 +16,6 @@
"express": "^5.2.1",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.562.0",
"matrix-widget-api": "^1.16.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},

View File

@@ -9,14 +9,7 @@ import { GifGrid } from './components/GifGrid';
import './styles/global.css';
function App() {
const [logs, setLogs] = useState<string[]>([]);
const addLog = (msg: string) => {
setLogs(prev => [`[${new Date().toLocaleTimeString()}] ${msg}`, ...prev].slice(0, 5));
console.log(msg);
};
const { theme, sendGif, ready, refreshPermissions } = useMatrixWidget(addLog);
const { theme, sendGif } = useMatrixWidget();
const { favorites, toggleFavorite, isFavorite } = useFavorites();
const [categories, setCategories] = useState<string[]>([]);
@@ -26,8 +19,6 @@ function App() {
const [loading, setLoading] = useState(false);
const [sendingState, setSendingState] = useState<{ id: string, status: 'sending' | 'sent' | 'error', errorMsg?: string } | null>(null);
// Apply theme
// Apply theme
useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
@@ -36,7 +27,6 @@ function App() {
// Load categories on mount
useEffect(() => {
gifService.getCategories().then(setCategories);
addLog("App mounted, waiting for Matrix...");
}, []);
// Fetch GIFs
@@ -60,7 +50,7 @@ function App() {
}
setGifs(results);
} catch (error: any) {
addLog(`Fetch error: ${error.message}`);
console.error(`Fetch error: ${error.message}`);
} finally {
setLoading(false);
}
@@ -84,22 +74,15 @@ function App() {
};
const handleGifSelect = async (gif: GifObject) => {
if (!ready) {
addLog("⚠️ Widget not ready, trying direct send...");
}
setSendingState({ id: gif.id, status: 'sending' });
addLog(`Sending GIF: ${gif.id}`);
try {
await sendGif(gif);
setSendingState({ id: gif.id, status: 'sent' });
addLog("Send success!");
setTimeout(() => setSendingState(null), 2000);
} catch (e: any) {
const msg = e.message || JSON.stringify(e);
setSendingState({ id: gif.id, status: 'error', errorMsg: msg });
addLog(`Send Failed: ${msg}`);
setTimeout(() => setSendingState(null), 5000);
}
};
@@ -108,81 +91,26 @@ function App() {
return (
<div className="app-container">
<div style={{
padding: '8px 12px',
fontSize: '12px',
color: ready ? '#4ECDC4' : '#FF6B6B',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<span>Status: {ready ? 'Connected' : 'Connecting...'}</span>
{sendingState && (
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
<span style={{
fontWeight: 'bold',
color: sendingState.status === 'error' ? '#FF6B6B' : '#FFEEAD'
}}>
{sendingState.status === 'sending' && 'Sending...'}
{sendingState.status === 'sent' && 'Sent!'}
{sendingState.status === 'error' && 'Failed'}
</span>
{sendingState.status === 'error' && (
<div style={{ display: 'flex', gap: '4px' }}>
<button
onClick={() => {
const id = prompt("Please paste the Widget ID from the logs (looks like !abc...):");
if (id) {
const url = new URL(window.location.href);
url.searchParams.set('widgetId', id);
window.location.href = url.toString();
}
}}
style={{
background: '#2F3136', border: '1px solid #555', borderRadius: '4px',
color: 'white', padding: '2px 6px', fontSize: '10px', cursor: 'pointer'
}}
>
Set ID
</button>
<button
onClick={() => {
addLog("Requesting permissions...");
refreshPermissions();
}}
style={{
background: '#5865F2', border: 'none', borderRadius: '4px',
color: 'white', padding: '2px 6px', fontSize: '10px', cursor: 'pointer'
}}
>
Fix Permissions
</button>
</div>
)}
</div>
)}
</div>
{/* Debug Log Box - Always visible */}
<div style={{
fontSize: '11px',
color: '#ccc',
padding: '8px 12px',
marginBottom: '8px',
fontFamily: 'monospace',
maxHeight: '120px',
minHeight: '60px',
overflowY: 'auto',
backgroundColor: 'rgba(0,0,0,0.3)',
borderRadius: '4px',
border: '1px solid rgba(255,255,255,0.1)'
position: 'fixed',
top: 0,
left: 0,
right: 0,
zIndex: 1000,
background: sendingState.status === 'error' ? '#FF6B6B' : '#4ECDC4',
color: '#1A1B1E',
padding: '8px',
textAlign: 'center',
fontWeight: 'bold',
fontSize: '14px',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
}}>
{logs.length === 0 ? (
<div style={{ color: '#666' }}>Waiting for logs...</div>
) : (
logs.map((log, i) => <div key={i}>{log}</div>)
)}
{sendingState.status === 'sending' && 'Sending GIF...'}
{sendingState.status === 'sent' && 'GIF Sent!'}
{sendingState.status === 'error' && `Error: ${sendingState.errorMsg || 'Failed to send'}`}
</div>
)}
<SearchBar onSearch={handleSearch} />

View File

@@ -1,94 +1,16 @@
import { useEffect, useState, useRef } from 'react';
import { WidgetApi } from 'matrix-widget-api';
import { useState } from 'react';
import type { GifObject } from '../types';
export const useMatrixWidget = (onLog?: (msg: string) => void) => {
const widgetApiRef = useRef<WidgetApi | null>(null);
export const useMatrixWidget = () => {
const [theme] = useState<'light' | 'dark'>(() => {
const themeParam = new URLSearchParams(window.location.search).get('theme');
return (themeParam === 'light' || themeParam === 'dark') ? themeParam : 'dark';
});
const [ready, setReady] = useState(false);
const initialized = useRef(false);
useEffect(() => {
if (initialized.current) return;
initialized.current = true;
const log = (msg: string) => {
console.log(`[Widget] ${msg}`);
onLog?.(msg);
};
const searchParams = new URLSearchParams(window.location.search);
const hashParams = new URLSearchParams(window.location.hash.substring(1));
log(`URL Search: ${window.location.search}`);
log(`URL Hash: ${window.location.hash}`);
const widgetId = searchParams.get('widgetId') || hashParams.get('widgetId');
// Decode the ID in case it was double-encoded or raw from URL
const finalId = widgetId ? decodeURIComponent(widgetId) : 'my-widget-id';
log(`Widget ID: ${finalId}`);
try {
const api = new WidgetApi(finalId);
log("Requesting capabilities...");
api.requestCapabilities([
'm.send_event:m.room.message',
'm.sticker',
'm.send_event:m.sticker',
]);
log("Starting Widget API...");
api.start();
api.on("ready", () => {
log("Widget API Ready!");
setReady(true);
});
api.on("error", (err: Error) => {
log(`Widget Error: ${err.message}`);
});
widgetApiRef.current = api;
// Set a timeout to warn if not ready after 5 seconds
setTimeout(() => {
if (!ready) {
log("⚠️ Still not ready after 5s. Are you running inside a Matrix widget?");
}
}, 5000);
} catch (error: any) {
log(`Init Error: ${error.message}`);
}
}, [onLog]);
const refreshPermissions = async () => {
if (!widgetApiRef.current) return;
onLog?.("Manual permission refresh triggered...");
try {
await widgetApiRef.current.requestCapabilities([
'm.sticker',
'm.send_event:m.sticker',
'm.send_event:m.room.message',
]);
onLog?.("Capabilities request sent.");
} catch (e) {
onLog?.(`Cap Request Error: ${e}`);
}
};
const sendGif = async (gif: GifObject) => {
const { tinygif } = gif.media_formats;
const title = gif.title || "GIF";
onLog?.(`Sending: ${title}`);
try {
// Get Matrix homeserver and access token from URL params
const searchParams = new URLSearchParams(window.location.search);
@@ -103,8 +25,6 @@ export const useMatrixWidget = (onLog?: (msg: string) => void) => {
// Use tinygif for smaller size
const gifUrl = tinygif.url;
onLog?.('Uploading to Matrix...');
// Upload GIF through our proxy
const uploadResponse = await fetch(
`/api/gif-upload?url=${encodeURIComponent(gifUrl)}&homeserver=${encodeURIComponent(homeserver)}&accessToken=${encodeURIComponent(accessToken)}`
@@ -117,8 +37,6 @@ export const useMatrixWidget = (onLog?: (msg: string) => void) => {
const { mxcUrl, size } = await uploadResponse.json();
onLog?.(`Uploaded ${(size / 1024).toFixed(1)}KB, sending...`);
// Send directly via Matrix Client-Server API
const txnId = `m${Date.now()}.${Math.random()}`;
const sendUrl = `${homeserver}/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/send/m.sticker/${txnId}`;
@@ -146,12 +64,11 @@ export const useMatrixWidget = (onLog?: (msg: string) => void) => {
throw new Error(error.error || 'Send failed');
}
onLog?.('✓ GIF sent!');
} catch (error: any) {
onLog?.(`✗ Failed: ${error.message}`);
console.error(`Failed to send GIF: ${error.message}`);
throw error;
}
};
return { theme, sendGif, ready, refreshPermissions };
return { theme, sendGif };
};