Compare commits
No commits in common. "7f8d78036a946c6ded7497b30a73042e99857766" and "d21a674197a86d7a47bff98e2d1dd1204bee0a32" have entirely different histories.
7f8d78036a
...
d21a674197
27
nginx.conf
27
nginx.conf
|
|
@ -18,32 +18,7 @@ server {
|
||||||
add_header X-XSS-Protection "1; mode=block" always;
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||||
|
|
||||||
# NEVER cache index.html and service worker - always fetch fresh
|
# Cache static assets
|
||||||
location = /index.html {
|
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
add_header Pragma "no-cache";
|
|
||||||
add_header Expires "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /sw.js {
|
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
add_header Pragma "no-cache";
|
|
||||||
add_header Expires "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /registerSW.js {
|
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
add_header Pragma "no-cache";
|
|
||||||
add_header Expires "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
location = /manifest.webmanifest {
|
|
||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
||||||
add_header Pragma "no-cache";
|
|
||||||
add_header Expires "0";
|
|
||||||
}
|
|
||||||
|
|
||||||
# Cache static assets with hashed filenames (immutable)
|
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
expires 1y;
|
expires 1y;
|
||||||
add_header Cache-Control "public, immutable";
|
add_header Cache-Control "public, immutable";
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const token = urlParams.get('token');
|
const token = urlParams.get('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
|
console.log('🔑 Access token found in URL');
|
||||||
setAccessTokenState(token);
|
setAccessTokenState(token);
|
||||||
// Optionally remove from URL to clean it up (but keep the token in state)
|
// Optionally remove from URL to clean it up (but keep the token in state)
|
||||||
// This prevents the token from being shared if someone copies the URL
|
// This prevents the token from being shared if someone copies the URL
|
||||||
|
|
@ -118,6 +119,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
boardPermissions: {},
|
boardPermissions: {},
|
||||||
currentBoardPermission: undefined,
|
currentBoardPermission: undefined,
|
||||||
});
|
});
|
||||||
|
console.log('🔐 Login successful - cleared permission cache, authChangedAt:', authChangedAtRef.current);
|
||||||
|
|
||||||
// Save session to localStorage if authenticated
|
// Save session to localStorage if authenticated
|
||||||
if (result.session.authed && result.session.username) {
|
if (result.session.authed && result.session.username) {
|
||||||
|
|
@ -163,6 +165,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
boardPermissions: {},
|
boardPermissions: {},
|
||||||
currentBoardPermission: undefined,
|
currentBoardPermission: undefined,
|
||||||
});
|
});
|
||||||
|
console.log('🔐 Registration successful - cleared permission cache, authChangedAt:', authChangedAtRef.current);
|
||||||
|
|
||||||
// Save session to localStorage if authenticated
|
// Save session to localStorage if authenticated
|
||||||
if (result.session.authed && result.session.username) {
|
if (result.session.authed && result.session.username) {
|
||||||
|
|
@ -178,7 +181,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Registration error:', error);
|
console.error('Register error:', error);
|
||||||
setSessionState(prev => ({
|
setSessionState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
@ -207,6 +210,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
boardPermissions: {},
|
boardPermissions: {},
|
||||||
currentBoardPermission: undefined,
|
currentBoardPermission: undefined,
|
||||||
});
|
});
|
||||||
|
console.log('🔐 Session cleared - marked auth as changed, authChangedAt:', authChangedAtRef.current);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -243,9 +247,13 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
// IMPORTANT: Check if auth state changed recently (within last 5 seconds)
|
// IMPORTANT: Check if auth state changed recently (within last 5 seconds)
|
||||||
// If so, bypass cache entirely to prevent stale callbacks from returning old cached values
|
// If so, bypass cache entirely to prevent stale callbacks from returning old cached values
|
||||||
const authChangedRecently = Date.now() - authChangedAtRef.current < 5000;
|
const authChangedRecently = Date.now() - authChangedAtRef.current < 5000;
|
||||||
|
if (authChangedRecently) {
|
||||||
|
console.log('🔐 Auth changed recently, bypassing permission cache');
|
||||||
|
}
|
||||||
|
|
||||||
// Check cache first (but only if no access token and auth didn't just change)
|
// Check cache first (but only if no access token and auth didn't just change)
|
||||||
if (!accessToken && !authChangedRecently && session.boardPermissions?.[boardId]) {
|
if (!accessToken && !authChangedRecently && session.boardPermissions?.[boardId]) {
|
||||||
|
console.log('🔐 Using cached permission for board:', boardId, session.boardPermissions[boardId]);
|
||||||
return session.boardPermissions[boardId];
|
return session.boardPermissions[boardId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,10 +272,20 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug: Log what we're sending
|
||||||
|
console.log('🔐 fetchBoardPermission:', {
|
||||||
|
boardId,
|
||||||
|
sessionAuthed: session.authed,
|
||||||
|
sessionUsername: session.username,
|
||||||
|
publicKeyUsed: publicKeyUsed ? `${publicKeyUsed.substring(0, 20)}...` : null,
|
||||||
|
hasAccessToken: !!accessToken
|
||||||
|
});
|
||||||
|
|
||||||
// Build URL with optional access token
|
// Build URL with optional access token
|
||||||
let url = `${WORKER_URL}/boards/${boardId}/permission`;
|
let url = `${WORKER_URL}/boards/${boardId}/permission`;
|
||||||
if (accessToken) {
|
if (accessToken) {
|
||||||
url += `?token=${encodeURIComponent(accessToken)}`;
|
url += `?token=${encodeURIComponent(accessToken)}`;
|
||||||
|
console.log('🔑 Including access token in permission check');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
|
|
@ -276,7 +294,9 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// Default to 'edit' for everyone (open by default) if API fails
|
console.error('Failed to fetch board permission:', response.status);
|
||||||
|
// NEW: Default to 'edit' for everyone (open by default)
|
||||||
|
console.log('🔐 Using default permission (API failed): edit');
|
||||||
return 'edit';
|
return 'edit';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,12 +310,27 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
isGlobalAdmin?: boolean; // Whether user is global admin
|
isGlobalAdmin?: boolean; // Whether user is global admin
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Debug: Log what we received
|
||||||
|
console.log('🔐 Permission response:', data);
|
||||||
|
|
||||||
|
if (data.grantedByToken) {
|
||||||
|
console.log('🔓 Permission granted via access token:', data.permission);
|
||||||
|
}
|
||||||
|
if (data.isGlobalAdmin) {
|
||||||
|
console.log('🔓 User is global admin');
|
||||||
|
}
|
||||||
|
|
||||||
// NEW PERMISSION MODEL (Dec 2024):
|
// NEW PERMISSION MODEL (Dec 2024):
|
||||||
// - Everyone (including anonymous) can EDIT by default
|
// - Everyone (including anonymous) can EDIT by default
|
||||||
// - Only protected boards restrict editing to listed editors
|
// - Only protected boards restrict editing to listed editors
|
||||||
// The backend now returns the correct permission, so we just use it directly
|
// The backend now returns the correct permission, so we just use it directly
|
||||||
let effectivePermission = data.permission;
|
let effectivePermission = data.permission;
|
||||||
|
|
||||||
|
// Log why view permission was given (for debugging protected boards)
|
||||||
|
if (data.permission === 'view' && data.isProtected) {
|
||||||
|
console.log('🔒 View-only: board is protected and user is not an editor');
|
||||||
|
}
|
||||||
|
|
||||||
// Cache the permission
|
// Cache the permission
|
||||||
setSessionState(prev => ({
|
setSessionState(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
|
|
@ -309,7 +344,8 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
return effectivePermission;
|
return effectivePermission;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching board permission:', error);
|
console.error('Error fetching board permission:', error);
|
||||||
// Default to 'edit' for everyone (open by default)
|
// NEW: Default to 'edit' for everyone (open by default)
|
||||||
|
console.log('🔐 Using default permission (error): edit');
|
||||||
return 'edit';
|
return 'edit';
|
||||||
}
|
}
|
||||||
}, [session.authed, session.username, session.boardPermissions, accessToken]);
|
}, [session.authed, session.username, session.boardPermissions, accessToken]);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultProps(): IVideoChatShape["props"] {
|
getDefaultProps(): IVideoChatShape["props"] {
|
||||||
return {
|
const props = {
|
||||||
roomUrl: null,
|
roomUrl: null,
|
||||||
w: 800,
|
w: 800,
|
||||||
h: 560, // Reduced from 600 to account for header (40px) and avoid scrollbars
|
h: 560, // Reduced from 600 to account for header (40px) and avoid scrollbars
|
||||||
|
|
@ -54,6 +54,8 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
pinnedToView: false,
|
pinnedToView: false,
|
||||||
tags: ['video-chat']
|
tags: ['video-chat']
|
||||||
};
|
};
|
||||||
|
console.log('🔧 getDefaultProps called, returning:', props);
|
||||||
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateMeetingToken(roomName: string) {
|
async generateMeetingToken(roomName: string) {
|
||||||
|
|
@ -70,6 +72,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
|
|
||||||
// For now, let's skip token generation and use a simpler approach
|
// For now, let's skip token generation and use a simpler approach
|
||||||
// We'll use the room URL directly and handle owner permissions differently
|
// We'll use the room URL directly and handle owner permissions differently
|
||||||
|
console.log('Skipping meeting token generation for now');
|
||||||
return `token_${roomName}_${Date.now()}`;
|
return `token_${roomName}_${Date.now()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,6 +90,8 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
roomId = localStorage.getItem('currentRoomId') || 'default-room';
|
roomId = localStorage.getItem('currentRoomId') || 'default-room';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('🔧 Using room ID:', roomId);
|
||||||
|
|
||||||
// Clear old storage entries that use the old boardId format
|
// Clear old storage entries that use the old boardId format
|
||||||
// This ensures we don't load old rooms with the wrong naming convention
|
// This ensures we don't load old rooms with the wrong naming convention
|
||||||
const oldStorageKeys = [
|
const oldStorageKeys = [
|
||||||
|
|
@ -97,6 +102,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
|
|
||||||
oldStorageKeys.forEach(key => {
|
oldStorageKeys.forEach(key => {
|
||||||
if (localStorage.getItem(key)) {
|
if (localStorage.getItem(key)) {
|
||||||
|
console.log(`Clearing old storage entry: ${key}`);
|
||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key);
|
||||||
localStorage.removeItem(`${key}_token`);
|
localStorage.removeItem(`${key}_token`);
|
||||||
}
|
}
|
||||||
|
|
@ -110,9 +116,11 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
if (existingRoomUrl && existingRoomUrl !== 'undefined' && existingToken) {
|
if (existingRoomUrl && existingRoomUrl !== 'undefined' && existingToken) {
|
||||||
// Check if the existing room URL uses the old naming pattern
|
// Check if the existing room URL uses the old naming pattern
|
||||||
if (existingRoomUrl.includes('board_page_page_') || existingRoomUrl.includes('page_page')) {
|
if (existingRoomUrl.includes('board_page_page_') || existingRoomUrl.includes('page_page')) {
|
||||||
|
console.log("Found old room URL format, clearing and creating new room:", existingRoomUrl);
|
||||||
localStorage.removeItem(storageKey);
|
localStorage.removeItem(storageKey);
|
||||||
localStorage.removeItem(`${storageKey}_token`);
|
localStorage.removeItem(`${storageKey}_token`);
|
||||||
} else {
|
} else {
|
||||||
|
console.log("Using existing room from storage:", existingRoomUrl);
|
||||||
await this.editor.updateShape<IVideoChatShape>({
|
await this.editor.updateShape<IVideoChatShape>({
|
||||||
id: shape.id,
|
id: shape.id,
|
||||||
type: shape.type,
|
type: shape.type,
|
||||||
|
|
@ -129,7 +137,10 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
|
|
||||||
if (shape.props.roomUrl !== null && shape.props.roomUrl !== 'undefined' && shape.props.meetingToken) {
|
if (shape.props.roomUrl !== null && shape.props.roomUrl !== 'undefined' && shape.props.meetingToken) {
|
||||||
// Check if the shape's room URL uses the old naming pattern
|
// Check if the shape's room URL uses the old naming pattern
|
||||||
if (!shape.props.roomUrl.includes('board_page_page_') && !shape.props.roomUrl.includes('page_page')) {
|
if (shape.props.roomUrl.includes('board_page_page_') || shape.props.roomUrl.includes('page_page')) {
|
||||||
|
console.log("Shape has old room URL format, will create new room:", shape.props.roomUrl);
|
||||||
|
} else {
|
||||||
|
console.log("Room already exists:", shape.props.roomUrl);
|
||||||
localStorage.setItem(storageKey, shape.props.roomUrl);
|
localStorage.setItem(storageKey, shape.props.roomUrl);
|
||||||
localStorage.setItem(`${storageKey}_token`, shape.props.meetingToken);
|
localStorage.setItem(`${storageKey}_token`, shape.props.meetingToken);
|
||||||
return;
|
return;
|
||||||
|
|
@ -140,6 +151,12 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
const workerUrl = WORKER_URL;
|
const workerUrl = WORKER_URL;
|
||||||
const apiKey = import.meta.env.VITE_DAILY_API_KEY;
|
const apiKey = import.meta.env.VITE_DAILY_API_KEY;
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
console.log('🔧 VideoChat Debug:');
|
||||||
|
console.log('WORKER_URL:', WORKER_URL);
|
||||||
|
console.log('workerUrl:', workerUrl);
|
||||||
|
console.log('apiKey exists:', !!apiKey);
|
||||||
|
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
throw new Error('Daily.co API key not configured');
|
throw new Error('Daily.co API key not configured');
|
||||||
}
|
}
|
||||||
|
|
@ -154,6 +171,22 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
const cleanId = shortId.replace(/[^A-Za-z0-9]/g, '');
|
const cleanId = shortId.replace(/[^A-Za-z0-9]/g, '');
|
||||||
const roomName = `canvas-${cleanId}`;
|
const roomName = `canvas-${cleanId}`;
|
||||||
|
|
||||||
|
console.log('🔧 Room name generation:');
|
||||||
|
console.log('Original roomId:', roomId);
|
||||||
|
console.log('Short ID:', shortId);
|
||||||
|
console.log('Clean ID:', cleanId);
|
||||||
|
console.log('Final roomName:', roomName);
|
||||||
|
|
||||||
|
console.log('🔧 Creating Daily.co room with:', {
|
||||||
|
name: roomName,
|
||||||
|
properties: {
|
||||||
|
enable_chat: true,
|
||||||
|
enable_screenshare: true,
|
||||||
|
start_video_off: true,
|
||||||
|
start_audio_off: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const response = await fetch(`${workerUrl}/daily/rooms`, {
|
const response = await fetch(`${workerUrl}/daily/rooms`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
|
@ -171,14 +204,19 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('🔧 Daily.co API response status:', response.status);
|
||||||
|
console.log('🔧 Daily.co API response ok:', response.ok);
|
||||||
|
|
||||||
let url: string;
|
let url: string;
|
||||||
let isNewRoom: boolean = false;
|
let isNewRoom: boolean = false;
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const error = await response.json() as any
|
const error = await response.json() as any
|
||||||
|
console.error('🔧 Daily.co API error:', error);
|
||||||
|
|
||||||
// Check if the room already exists
|
// Check if the room already exists
|
||||||
if (response.status === 400 && error.info && error.info.includes('already exists')) {
|
if (response.status === 400 && error.info && error.info.includes('already exists')) {
|
||||||
|
console.log('🔧 Room already exists, connecting to existing room:', roomName);
|
||||||
isNewRoom = false;
|
isNewRoom = false;
|
||||||
|
|
||||||
// Try to get the existing room info from Daily.co API
|
// Try to get the existing room info from Daily.co API
|
||||||
|
|
@ -193,10 +231,17 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
if (getRoomResponse.ok) {
|
if (getRoomResponse.ok) {
|
||||||
const roomData = await getRoomResponse.json() as any;
|
const roomData = await getRoomResponse.json() as any;
|
||||||
url = roomData.url;
|
url = roomData.url;
|
||||||
|
console.log('🔧 Retrieved existing room URL:', url);
|
||||||
} else {
|
} else {
|
||||||
|
// If we can't get room info, construct the URL
|
||||||
|
// This is a fallback - ideally we'd get it from the API
|
||||||
|
console.warn('🔧 Could not get room info, constructing URL (this may not work)');
|
||||||
|
// We'll need to construct it, but we don't have the domain
|
||||||
|
// For now, throw an error and let the user know
|
||||||
throw new Error(`Room ${roomName} already exists but could not retrieve room URL. Please contact support.`);
|
throw new Error(`Room ${roomName} already exists but could not retrieve room URL. Please contact support.`);
|
||||||
}
|
}
|
||||||
} catch (getRoomError) {
|
} catch (getRoomError) {
|
||||||
|
console.error('🔧 Error getting existing room:', getRoomError);
|
||||||
throw new Error(`Room ${roomName} already exists but could not connect to it: ${(getRoomError as Error).message}`);
|
throw new Error(`Room ${roomName} already exists but could not connect to it: ${(getRoomError as Error).message}`);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -207,20 +252,35 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
// Room was created successfully
|
// Room was created successfully
|
||||||
isNewRoom = true;
|
isNewRoom = true;
|
||||||
const data = (await response.json()) as DailyApiResponse;
|
const data = (await response.json()) as DailyApiResponse;
|
||||||
|
console.log('🔧 Daily.co API response data:', data);
|
||||||
url = data.url;
|
url = data.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
|
console.error('🔧 Room URL is missing');
|
||||||
throw new Error("Room URL is missing")
|
throw new Error("Room URL is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('🔧 Room URL from API:', url);
|
||||||
|
|
||||||
// Generate meeting token for the owner
|
// Generate meeting token for the owner
|
||||||
|
// First ensure the room exists, then generate token
|
||||||
const meetingToken = await this.generateMeetingToken(roomName);
|
const meetingToken = await this.generateMeetingToken(roomName);
|
||||||
|
|
||||||
// Store the room URL and token in localStorage
|
// Store the room URL and token in localStorage
|
||||||
localStorage.setItem(storageKey, url);
|
localStorage.setItem(storageKey, url);
|
||||||
localStorage.setItem(`${storageKey}_token`, meetingToken);
|
localStorage.setItem(`${storageKey}_token`, meetingToken);
|
||||||
|
|
||||||
|
if (isNewRoom) {
|
||||||
|
console.log("Room created successfully:", url)
|
||||||
|
} else {
|
||||||
|
console.log("Connected to existing room:", url)
|
||||||
|
}
|
||||||
|
console.log("Meeting token generated:", meetingToken)
|
||||||
|
console.log("Updating shape with new URL and token")
|
||||||
|
// Set isOwner to true only if we created the room, false if we connected to existing
|
||||||
|
console.log("Setting isOwner to", isNewRoom)
|
||||||
|
|
||||||
await this.editor.updateShape<IVideoChatShape>({
|
await this.editor.updateShape<IVideoChatShape>({
|
||||||
id: shape.id,
|
id: shape.id,
|
||||||
type: shape.type,
|
type: shape.type,
|
||||||
|
|
@ -231,6 +291,10 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
isOwner: isNewRoom, // Only owner if we created the room
|
isOwner: isNewRoom, // Only owner if we created the room
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log("Shape updated:", this.editor.getShape(shape.id))
|
||||||
|
const updatedShape = this.editor.getShape(shape.id) as IVideoChatShape;
|
||||||
|
console.log("Updated shape isOwner:", updatedShape?.props.isOwner)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error in ensureRoomExists:", error)
|
console.error("Error in ensureRoomExists:", error)
|
||||||
throw error
|
throw error
|
||||||
|
|
@ -572,17 +636,20 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
console.error('Iframe loading error:', e);
|
console.error('Iframe loading error:', e);
|
||||||
setIframeError(true);
|
setIframeError(true);
|
||||||
if (retryCount < 2) {
|
if (retryCount < 2) {
|
||||||
|
console.log(`Retrying iframe load (attempt ${retryCount + 1})`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setRetryCount(prev => prev + 1);
|
setRetryCount(prev => prev + 1);
|
||||||
setIframeError(false);
|
setIframeError(false);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
} else {
|
} else {
|
||||||
|
console.log('Switching to fallback iframe configuration');
|
||||||
setUseFallback(true);
|
setUseFallback(true);
|
||||||
setIframeError(false);
|
setIframeError(false);
|
||||||
setRetryCount(0);
|
setRetryCount(0);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
|
console.log('Iframe loaded successfully');
|
||||||
setIframeError(false);
|
setIframeError(false);
|
||||||
setRetryCount(0);
|
setRetryCount(0);
|
||||||
}}
|
}}
|
||||||
|
|
@ -608,6 +675,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
console.error('Fallback iframe loading error:', e);
|
console.error('Fallback iframe loading error:', e);
|
||||||
setIframeError(true);
|
setIframeError(true);
|
||||||
if (retryCount < 3) {
|
if (retryCount < 3) {
|
||||||
|
console.log(`Retrying fallback iframe load (attempt ${retryCount + 1})`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setRetryCount(prev => prev + 1);
|
setRetryCount(prev => prev + 1);
|
||||||
setIframeError(false);
|
setIframeError(false);
|
||||||
|
|
@ -617,6 +685,7 @@ export class VideoChatShape extends BaseBoxShapeUtil<IVideoChatShape> {
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onLoad={() => {
|
onLoad={() => {
|
||||||
|
console.log('Fallback iframe loaded successfully');
|
||||||
setIframeError(false);
|
setIframeError(false);
|
||||||
setRetryCount(0);
|
setRetryCount(0);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ export default defineConfig(({ mode }) => {
|
||||||
registerType: 'autoUpdate',
|
registerType: 'autoUpdate',
|
||||||
injectRegister: 'auto',
|
injectRegister: 'auto',
|
||||||
workbox: {
|
workbox: {
|
||||||
// Force the service worker to take control immediately
|
|
||||||
skipWaiting: true,
|
|
||||||
clientsClaim: true,
|
|
||||||
// Cache all static assets
|
// Cache all static assets
|
||||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2,wasm}'],
|
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2,wasm}'],
|
||||||
// Increase the limit for large chunks (Board is ~8MB with tldraw, automerge, etc.)
|
// Increase the limit for large chunks (Board is ~8MB with tldraw, automerge, etc.)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue