fix: prevent My Apps crash when installing apps + add filebrowser to demo

The My Apps page went blank after installing apps because pkg['static-files'].icon
was accessed without optional chaining on dynamically installed packages that lack
the static-files property.

- Make static-files optional in PackageDataEntry type
- Add defensive ?.icon access with fallback in Apps.vue and AppDetails.vue
- Add filebrowser to mock backend staticDevApps (enables Cloud page in demo)
- Expand portMappings and marketplaceMetadata for all marketplace apps
- installPackage now uses staticApp() format for consistent data shape

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-09 17:09:59 +00:00
parent 9c7ffbb263
commit a2aa9657b1
24 changed files with 1200 additions and 141 deletions

View File

@@ -34,9 +34,10 @@ export class WebSocketClient {
this.visibilityChangeHandler = () => {
if (document.visibilityState === 'visible') {
console.log('[WebSocket] Page became visible, checking connection...')
// Reconnect if connection was lost while tab was hidden
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
// Only reconnect if we haven't been explicitly disconnected
if (this.shouldReconnect && (!this.ws || this.ws.readyState !== WebSocket.OPEN)) {
console.log('[WebSocket] Connection lost while hidden, reconnecting...')
this.reconnectAttempts = 0
this.connect().catch(err => {
console.error('[WebSocket] Failed to reconnect on visibility change:', err)
})
@@ -47,8 +48,11 @@ export class WebSocketClient {
// Handle network online/offline events
this.onlineHandler = () => {
// Only reconnect if we haven't been explicitly disconnected
if (!this.shouldReconnect) return
console.log('[WebSocket] Network came online, reconnecting...')
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
this.reconnectAttempts = 0
this.connect().catch(err => {
console.error('[WebSocket] Failed to reconnect when network came online:', err)
})
@@ -108,10 +112,11 @@ export class WebSocketClient {
return
}
// Reset shouldReconnect flag when explicitly connecting
this.shouldReconnect = true
// Reset reconnect attempts only if we're explicitly connecting (not auto-reconnecting)
// This allows reconnection attempts to continue
// Only enable reconnect if not explicitly disconnected
// (shouldReconnect is set to false by disconnect())
if (this.shouldReconnect !== false) {
this.shouldReconnect = true
}
// In development, Vite proxies /ws to the backend
// In production, use the same host as the page
@@ -262,10 +267,10 @@ export class WebSocketClient {
// Check if we've received a message recently
const timeSinceLastMessage = Date.now() - this.lastMessageTime
// If no message for more than 60 seconds, assume connection is stale
if (timeSinceLastMessage > 60000) {
console.warn('[WebSocket] No messages for 60s, reconnecting...')
// If no message for more than 5 minutes, assume connection is stale
if (timeSinceLastMessage > 300000) {
console.warn('[WebSocket] No messages for 5m, reconnecting...')
this.ws.close()
return
}