All checks were successful
Build / build (push) Successful in 1m31s
Previously disabled due to GraphQL errors. Now re-enabled with comprehensive error logging to diagnose the specific issue. Changes to discordWidget.ts: - Wrapped initialization in try-catch with detailed error logging - Added step-by-step console logs through initialization process - Added error event listener on the widget - Added window.onerror handler to catch widgetbot/GraphQL errors Changes to main.ts: - Uncommented Discord widget initialization - Added detailed error logging in catch block - Log error type, message, stack, and GraphQL response if available Next steps: - Load the application in browser - Check console for detailed error messages - Identify specific GraphQL query/mutation causing issues - Server ID: 1112846185913401475 - Channel ID: 1437561367908581406 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
238 lines
6.0 KiB
TypeScript
238 lines
6.0 KiB
TypeScript
/**
|
|
* Discord Widget Integration using Widgetbot Crate
|
|
* Dynamically loads the widget script to avoid npm bundling issues
|
|
*/
|
|
|
|
export interface DiscordWidgetOptions {
|
|
server: string;
|
|
channel: string;
|
|
location?: string[];
|
|
color?: string;
|
|
glyph?: string[];
|
|
notifications?: boolean;
|
|
indicator?: boolean;
|
|
allChannelNotifications?: boolean;
|
|
}
|
|
|
|
export class DiscordWidget {
|
|
private crate: any = null;
|
|
private scriptLoaded = false;
|
|
private isVisible = false;
|
|
|
|
/**
|
|
* Initialize the Discord widget
|
|
* @param options - Widget configuration
|
|
*/
|
|
async initialize(options: DiscordWidgetOptions): Promise<void> {
|
|
try {
|
|
// Load the Crate script if not already loaded
|
|
if (!this.scriptLoaded) {
|
|
console.log('[DiscordWidget] Loading Crate script...');
|
|
await this.loadCrateScript();
|
|
this.scriptLoaded = true;
|
|
console.log('[DiscordWidget] Crate script loaded');
|
|
}
|
|
|
|
// Wait for Crate to be available on window
|
|
console.log('[DiscordWidget] Waiting for Crate constructor...');
|
|
await this.waitForCrate();
|
|
console.log('[DiscordWidget] Crate constructor available');
|
|
|
|
// Initialize the Crate widget
|
|
const defaultOptions: DiscordWidgetOptions = {
|
|
location: ['bottom', 'right'],
|
|
color: '#7289DA',
|
|
glyph: ['💬', '✖️'],
|
|
notifications: true,
|
|
indicator: true,
|
|
...options
|
|
};
|
|
|
|
console.log('[DiscordWidget] Initializing Crate with options:', defaultOptions);
|
|
|
|
// @ts-ignore - Crate is loaded from CDN
|
|
this.crate = new window.Crate(defaultOptions);
|
|
|
|
console.log('[DiscordWidget] Crate instance created, setting up event listeners...');
|
|
this.setupEventListeners();
|
|
console.log('[DiscordWidget] Successfully initialized');
|
|
} catch (error) {
|
|
console.error('[DiscordWidget] Initialization failed:', error);
|
|
console.error('[DiscordWidget] Error details:', {
|
|
name: error?.constructor?.name,
|
|
message: error?.message,
|
|
stack: error?.stack
|
|
});
|
|
throw error; // Re-throw to be caught by caller
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Dynamically load the Crate script from CDN
|
|
*/
|
|
private loadCrateScript(): Promise<void> {
|
|
return new Promise((resolve, reject) => {
|
|
// Check if script already exists
|
|
const existingScript = document.querySelector('script[src*="widgetbot"]');
|
|
if (existingScript) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
const script = document.createElement('script');
|
|
script.src = 'https://cdn.jsdelivr.net/npm/@widgetbot/crate@3';
|
|
script.async = true;
|
|
script.defer = true;
|
|
|
|
script.onload = () => {
|
|
console.log('[DiscordWidget] Script loaded successfully');
|
|
resolve();
|
|
};
|
|
|
|
script.onerror = () => {
|
|
console.error('[DiscordWidget] Failed to load script');
|
|
reject(new Error('Failed to load Widgetbot Crate script'));
|
|
};
|
|
|
|
document.head.appendChild(script);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Wait for Crate constructor to be available on window
|
|
*/
|
|
private waitForCrate(): Promise<void> {
|
|
return new Promise((resolve) => {
|
|
const checkCrate = () => {
|
|
// @ts-ignore
|
|
if (window.Crate) {
|
|
resolve();
|
|
} else {
|
|
setTimeout(checkCrate, 50);
|
|
}
|
|
};
|
|
checkCrate();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Setup event listeners for widget events
|
|
*/
|
|
private setupEventListeners(): void {
|
|
if (!this.crate) return;
|
|
|
|
// Listen for when user signs in
|
|
this.crate.on('signIn', (user: any) => {
|
|
console.log('[DiscordWidget] User signed in:', user.username);
|
|
});
|
|
|
|
// Listen for widget visibility changes
|
|
this.crate.on('toggleChat', (visible: boolean) => {
|
|
this.isVisible = visible;
|
|
console.log('[DiscordWidget] Chat visibility:', visible);
|
|
});
|
|
|
|
// Listen for any errors from the widget
|
|
this.crate.on('error', (error: any) => {
|
|
console.error('[DiscordWidget] Widget error event:', error);
|
|
});
|
|
|
|
// Monitor window errors that might be related to Discord widget
|
|
const originalErrorHandler = window.onerror;
|
|
window.onerror = (message, source, lineno, colno, error) => {
|
|
if (source?.includes('widgetbot') || message?.toString().includes('GraphQL')) {
|
|
console.error('[DiscordWidget] Window error (possibly related):', {
|
|
message,
|
|
source,
|
|
lineno,
|
|
colno,
|
|
error
|
|
});
|
|
}
|
|
// Call original handler if it existed
|
|
if (originalErrorHandler) {
|
|
return originalErrorHandler(message, source, lineno, colno, error);
|
|
}
|
|
return false;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Toggle the Discord chat widget
|
|
*/
|
|
toggle(): void {
|
|
if (this.crate) {
|
|
this.crate.toggle();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show a notification on the widget button
|
|
* @param message - Notification message
|
|
*/
|
|
notify(message: string): void {
|
|
if (this.crate) {
|
|
this.crate.notify(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show the widget
|
|
*/
|
|
show(): void {
|
|
if (this.crate && !this.isVisible) {
|
|
this.crate.show();
|
|
this.isVisible = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hide the widget
|
|
*/
|
|
hide(): void {
|
|
if (this.crate && this.isVisible) {
|
|
this.crate.hide();
|
|
this.isVisible = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if widget is currently visible
|
|
*/
|
|
getIsVisible(): boolean {
|
|
return this.isVisible;
|
|
}
|
|
|
|
/**
|
|
* Emit a custom event to the widget
|
|
* @param event - Event name
|
|
* @param data - Event data
|
|
*/
|
|
emit(event: string, data?: any): void {
|
|
if (this.crate) {
|
|
this.crate.emit(event, data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Listen for widget events
|
|
* @param event - Event name
|
|
* @param callback - Event callback
|
|
*/
|
|
on(event: string, callback: (data: any) => void): void {
|
|
if (this.crate) {
|
|
this.crate.on(event, callback);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a message to the Discord channel (if user is signed in)
|
|
* @param message - Message text
|
|
*/
|
|
sendMessage(message: string): void {
|
|
if (this.crate) {
|
|
this.emit('sendMessage', message);
|
|
}
|
|
}
|
|
}
|