Resruiin
This commit is contained in:
@@ -39,7 +39,6 @@
|
|||||||
"vitest-browser-svelte": "^2.0.2"
|
"vitest-browser-svelte": "^2.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inlang/paraglide-js": "^2.10.0",
|
|
||||||
"@supabase/ssr": "^0.8.0",
|
"@supabase/ssr": "^0.8.0",
|
||||||
"@supabase/supabase-js": "^2.94.0",
|
"@supabase/supabase-js": "^2.94.0",
|
||||||
"@tanstack/svelte-virtual": "^3.13.18",
|
"@tanstack/svelte-virtual": "^3.13.18",
|
||||||
|
|||||||
12
src/app.html
12
src/app.html
@@ -1,13 +1,14 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
||||||
<html lang="%paraglide.lang%">
|
<html lang="%paraglide.lang%">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
<meta
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1"
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
/>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
@@ -22,4 +23,5 @@
|
|||||||
<body data-sveltekit-preload-data="tap">
|
<body data-sveltekit-preload-data="tap">
|
||||||
<div style="display: contents">%sveltekit.body%</div>
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
|
</html>
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
import { Button, Input } from "$lib/components/ui";
|
import { Button, Input } from "$lib/components/ui";
|
||||||
import { createRoom } from "$lib/matrix";
|
import { createRoom } from "$lib/matrix";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { createLogger, getErrorMessage } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('matrix:room');
|
||||||
import { syncRoomsFromEvent, selectRoom } from "$lib/stores/matrix";
|
import { syncRoomsFromEvent, selectRoom } from "$lib/stores/matrix";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -35,9 +38,9 @@
|
|||||||
roomName = "";
|
roomName = "";
|
||||||
isDirect = false;
|
isDirect = false;
|
||||||
onClose();
|
onClose();
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to create room:", e);
|
log.error('Failed to create room', { error: e });
|
||||||
toasts.error(e.message || "Failed to create room");
|
toasts.error(getErrorMessage(e, 'Failed to create room'));
|
||||||
} finally {
|
} finally {
|
||||||
isCreating = false;
|
isCreating = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
import { Button, Input } from "$lib/components/ui";
|
import { Button, Input } from "$lib/components/ui";
|
||||||
import { createSpace, getSpaces } from "$lib/matrix";
|
import { createSpace, getSpaces } from "$lib/matrix";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { createLogger, getErrorMessage } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('matrix:space');
|
||||||
import { syncRoomsFromEvent } from "$lib/stores/matrix";
|
import { syncRoomsFromEvent } from "$lib/stores/matrix";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -45,9 +48,9 @@
|
|||||||
spaceTopic = "";
|
spaceTopic = "";
|
||||||
isPublic = false;
|
isPublic = false;
|
||||||
onClose();
|
onClose();
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to create space:", e);
|
log.error('Failed to create space', { error: e });
|
||||||
toasts.error(e.message || "Failed to create space");
|
toasts.error(getErrorMessage(e, 'Failed to create space'));
|
||||||
} finally {
|
} finally {
|
||||||
isCreating = false;
|
isCreating = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
import EmojiPicker from "$lib/components/ui/EmojiPicker.svelte";
|
import EmojiPicker from "$lib/components/ui/EmojiPicker.svelte";
|
||||||
import { convertEmojiShortcodes } from "$lib/utils/emojiData";
|
import { convertEmojiShortcodes } from "$lib/utils/emojiData";
|
||||||
import { getTwemojiUrl } from "$lib/utils/twemoji";
|
import { getTwemojiUrl } from "$lib/utils/twemoji";
|
||||||
|
import { createLogger, getErrorMessage } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('matrix:input');
|
||||||
|
|
||||||
// Emoji detection regex
|
// Emoji detection regex
|
||||||
const emojiRegex =
|
const emojiRegex =
|
||||||
@@ -134,11 +137,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send typing indicator
|
// Send typing indicator
|
||||||
setTyping(roomId, true).catch(console.error);
|
setTyping(roomId, true).catch((e) => log.error('Failed to send typing', { error: e }));
|
||||||
|
|
||||||
// Stop typing after 3 seconds of no input
|
// Stop typing after 3 seconds of no input
|
||||||
typingTimeout = setTimeout(() => {
|
typingTimeout = setTimeout(() => {
|
||||||
setTyping(roomId, false).catch(console.error);
|
setTyping(roomId, false).catch((e) => log.error('Failed to stop typing', { error: e }));
|
||||||
}, 3000);
|
}, 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +419,7 @@
|
|||||||
clearTimeout(typingTimeout);
|
clearTimeout(typingTimeout);
|
||||||
typingTimeout = null;
|
typingTimeout = null;
|
||||||
}
|
}
|
||||||
setTyping(roomId, false).catch(console.error);
|
setTyping(roomId, false).catch((e) => log.error('Failed to stop typing', { error: e }));
|
||||||
|
|
||||||
// Create a temporary event ID for the pending message
|
// Create a temporary event ID for the pending message
|
||||||
const tempEventId = `pending-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
const tempEventId = `pending-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
@@ -462,11 +465,11 @@
|
|||||||
// If no event ID returned, just mark as not pending
|
// If no event ID returned, just mark as not pending
|
||||||
confirmPendingMessage(roomId, tempEventId, tempEventId);
|
confirmPendingMessage(roomId, tempEventId, tempEventId);
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to send message:", e);
|
log.error('Failed to send message', { error: e });
|
||||||
// Remove the pending message on failure
|
// Remove the pending message on failure
|
||||||
removePendingMessage(roomId, tempEventId);
|
removePendingMessage(roomId, tempEventId);
|
||||||
toasts.error(e.message || "Failed to send message");
|
toasts.error(getErrorMessage(e, 'Failed to send message'));
|
||||||
} finally {
|
} finally {
|
||||||
isSending = false;
|
isSending = false;
|
||||||
// Refocus after DOM settles from optimistic update
|
// Refocus after DOM settles from optimistic update
|
||||||
@@ -497,9 +500,9 @@
|
|||||||
const contentUri = await uploadFile(file);
|
const contentUri = await uploadFile(file);
|
||||||
await sendFileMessage(roomId, file, contentUri);
|
await sendFileMessage(roomId, file, contentUri);
|
||||||
toasts.success("File sent!");
|
toasts.success("File sent!");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to upload file:", e);
|
log.error('Failed to upload file', { error: e });
|
||||||
toasts.error(e.message || "Failed to upload file");
|
toasts.error(getErrorMessage(e, 'Failed to upload file'));
|
||||||
} finally {
|
} finally {
|
||||||
isUploading = false;
|
isUploading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
import { Avatar } from "$lib/components/ui";
|
import { Avatar } from "$lib/components/ui";
|
||||||
import { setRoomName, setRoomTopic, setRoomAvatar } from "$lib/matrix";
|
import { setRoomName, setRoomTopic, setRoomAvatar } from "$lib/matrix";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { createLogger } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('matrix:settings');
|
||||||
import { syncRoomsFromEvent } from "$lib/stores/matrix";
|
import { syncRoomsFromEvent } from "$lib/stores/matrix";
|
||||||
import type { RoomSummary } from "$lib/matrix/types";
|
import type { RoomSummary } from "$lib/matrix/types";
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@
|
|||||||
toasts.success("Room settings updated");
|
toasts.success("Room settings updated");
|
||||||
onClose();
|
onClose();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to update room settings:", e);
|
log.error('Failed to update room settings', { error: e });
|
||||||
toasts.error("Failed to update room settings");
|
toasts.error("Failed to update room settings");
|
||||||
} finally {
|
} finally {
|
||||||
isSaving = false;
|
isSaving = false;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
import { Avatar } from '$lib/components/ui';
|
import { Avatar } from '$lib/components/ui';
|
||||||
import { searchUsers, createDirectMessage } from '$lib/matrix';
|
import { searchUsers, createDirectMessage } from '$lib/matrix';
|
||||||
import { toasts } from '$lib/stores/ui';
|
import { toasts } from '$lib/stores/ui';
|
||||||
|
import { createLogger, getErrorMessage } from '$lib/utils/logger';
|
||||||
|
|
||||||
|
const log = createLogger('matrix:dm');
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
@@ -29,7 +32,7 @@
|
|||||||
try {
|
try {
|
||||||
searchResults = await searchUsers(searchQuery);
|
searchResults = await searchUsers(searchQuery);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Search failed:', e);
|
log.error('Search failed', { error: e });
|
||||||
} finally {
|
} finally {
|
||||||
isSearching = false;
|
isSearching = false;
|
||||||
}
|
}
|
||||||
@@ -43,9 +46,9 @@
|
|||||||
toasts.success('Direct message started!');
|
toasts.success('Direct message started!');
|
||||||
onDMCreated(roomId);
|
onDMCreated(roomId);
|
||||||
onClose();
|
onClose();
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error('Failed to create DM:', e);
|
log.error('Failed to create DM', { error: e });
|
||||||
toasts.error(e.message || 'Failed to start direct message');
|
toasts.error(getErrorMessage(e, 'Failed to start direct message'));
|
||||||
} finally {
|
} finally {
|
||||||
isCreating = false;
|
isCreating = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { syncState, syncError, clearState } from "$lib/stores/matrix";
|
import { syncState, syncError, clearState } from "$lib/stores/matrix";
|
||||||
import { clearAllCache } from "$lib/cache";
|
import { clearAllCache } from "$lib/cache";
|
||||||
|
import { createLogger } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('matrix:sync');
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onHardRefresh?: () => void;
|
onHardRefresh?: () => void;
|
||||||
@@ -43,7 +46,7 @@
|
|||||||
// Reload the page for clean state
|
// Reload the page for clean state
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[SyncRecovery] Hard refresh failed:", error);
|
log.error('Hard refresh failed', { error });
|
||||||
isRefreshing = false;
|
isRefreshing = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
import { createDirectMessage } from '$lib/matrix';
|
import { createDirectMessage } from '$lib/matrix';
|
||||||
import { userPresence } from '$lib/stores/matrix';
|
import { userPresence } from '$lib/stores/matrix';
|
||||||
import { toasts } from '$lib/stores/ui';
|
import { toasts } from '$lib/stores/ui';
|
||||||
|
import { createLogger } from '$lib/utils/logger';
|
||||||
|
|
||||||
|
const log = createLogger('matrix:profile');
|
||||||
import type { RoomMember } from '$lib/matrix/types';
|
import type { RoomMember } from '$lib/matrix/types';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -35,7 +38,7 @@
|
|||||||
onStartDM?.(roomId);
|
onStartDM?.(roomId);
|
||||||
onClose();
|
onClose();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to start DM:', e);
|
log.error('Failed to start DM', { error: e });
|
||||||
toasts.error('Failed to start direct message');
|
toasts.error('Failed to start direct message');
|
||||||
} finally {
|
} finally {
|
||||||
isStartingDM = false;
|
isStartingDM = false;
|
||||||
|
|||||||
@@ -318,7 +318,7 @@
|
|||||||
{#if showAddItemModal}
|
{#if showAddItemModal}
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddItemModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddItemModal = false)}>
|
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddItemModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddItemModal = false)}>
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
||||||
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-md space-y-4" onclick={(e) => e.stopPropagation()}>
|
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-md space-y-4" onclick={(e) => e.stopPropagation()}>
|
||||||
<h3 class="text-body font-heading text-white">{editingItem ? 'Edit' : 'Add'} Budget Item</h3>
|
<h3 class="text-body font-heading text-white">{editingItem ? 'Edit' : 'Add'} Budget Item</h3>
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@
|
|||||||
{#if showAddCategoryModal}
|
{#if showAddCategoryModal}
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddCategoryModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddCategoryModal = false)}>
|
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddCategoryModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddCategoryModal = false)}>
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
||||||
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-sm space-y-4" onclick={(e) => e.stopPropagation()}>
|
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-sm space-y-4" onclick={(e) => e.stopPropagation()}>
|
||||||
<h3 class="text-body font-heading text-white">Add Category</h3>
|
<h3 class="text-body font-heading text-white">Add Category</h3>
|
||||||
|
|
||||||
@@ -399,10 +399,11 @@
|
|||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
{#each CATEGORY_COLORS as color}
|
{#each CATEGORY_COLORS as color}
|
||||||
<button
|
<button
|
||||||
class="w-6 h-6 rounded-full border-2 transition-all {newCategoryColor === color ? 'border-white scale-110' : 'border-transparent'}"
|
class="w-6 h-6 rounded-full border-2 transition-all {newCategoryColor === color ? 'border-white scale-110' : 'border-transparent'}"
|
||||||
style="background-color: {color}"
|
style="background-color: {color}"
|
||||||
onclick={() => (newCategoryColor = color)}
|
onclick={() => (newCategoryColor = color)}
|
||||||
></button>
|
aria-label="Select color {color}"
|
||||||
|
></button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -422,7 +422,7 @@
|
|||||||
{#if showAddSponsorModal}
|
{#if showAddSponsorModal}
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddSponsorModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddSponsorModal = false)}>
|
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddSponsorModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddSponsorModal = false)}>
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
||||||
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-md space-y-4 max-h-[80vh] overflow-auto" onclick={(e) => e.stopPropagation()}>
|
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-md space-y-4 max-h-[80vh] overflow-auto" onclick={(e) => e.stopPropagation()}>
|
||||||
<h3 class="text-body font-heading text-white">{editingSponsor ? 'Edit' : 'Add'} Sponsor</h3>
|
<h3 class="text-body font-heading text-white">{editingSponsor ? 'Edit' : 'Add'} Sponsor</h3>
|
||||||
|
|
||||||
@@ -508,7 +508,7 @@
|
|||||||
{#if showAddTierModal}
|
{#if showAddTierModal}
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddTierModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddTierModal = false)}>
|
<div class="fixed inset-0 z-[60] bg-black/60 flex items-center justify-center p-4" onclick={() => (showAddTierModal = false)} onkeydown={(e) => e.key === 'Escape' && (showAddTierModal = false)}>
|
||||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
<!-- svelte-ignore a11y_no_static_element_interactions a11y_click_events_have_key_events -->
|
||||||
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-sm space-y-4" onclick={(e) => e.stopPropagation()}>
|
<div class="bg-surface rounded-2xl border border-light/10 p-5 w-full max-w-sm space-y-4" onclick={(e) => e.stopPropagation()}>
|
||||||
<h3 class="text-body font-heading text-white">Manage Tiers</h3>
|
<h3 class="text-body font-heading text-white">Manage Tiers</h3>
|
||||||
|
|
||||||
@@ -528,10 +528,11 @@
|
|||||||
<div class="flex gap-1.5">
|
<div class="flex gap-1.5">
|
||||||
{#each TIER_COLORS as color}
|
{#each TIER_COLORS as color}
|
||||||
<button
|
<button
|
||||||
class="w-6 h-6 rounded-full border-2 transition-all {tierColor === color ? 'border-white scale-110' : 'border-transparent'}"
|
class="w-6 h-6 rounded-full border-2 transition-all {tierColor === color ? 'border-white scale-110' : 'border-transparent'}"
|
||||||
style="background-color: {color}"
|
style="background-color: {color}"
|
||||||
onclick={() => (tierColor = color)}
|
onclick={() => (tierColor = color)}
|
||||||
></button>
|
aria-label="Select color {color}"
|
||||||
|
></button>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ import {
|
|||||||
type PinnedEventsContent,
|
type PinnedEventsContent,
|
||||||
type RoomAvatarContent,
|
type RoomAvatarContent,
|
||||||
} from './sdk-types';
|
} from './sdk-types';
|
||||||
|
import { createLogger } from '$lib/utils/logger';
|
||||||
|
|
||||||
|
const log = createLogger('matrix:client');
|
||||||
|
|
||||||
// Matrix message content types
|
// Matrix message content types
|
||||||
interface MessageContent extends IContent {
|
interface MessageContent extends IContent {
|
||||||
@@ -81,7 +84,7 @@ export interface LoginWithPasswordParams {
|
|||||||
*/
|
*/
|
||||||
export async function initMatrixClient(credentials: LoginCredentials): Promise<MatrixClient> {
|
export async function initMatrixClient(credentials: LoginCredentials): Promise<MatrixClient> {
|
||||||
if (client) {
|
if (client) {
|
||||||
console.warn('Matrix client already initialized, stopping existing client');
|
log.warn('Matrix client already initialized, stopping existing client');
|
||||||
await stopClient();
|
await stopClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,11 +106,11 @@ export async function initMatrixClient(credentials: LoginCredentials): Promise<M
|
|||||||
// Check if crypto module is available before trying to init
|
// Check if crypto module is available before trying to init
|
||||||
if (typeof client.initRustCrypto === 'function') {
|
if (typeof client.initRustCrypto === 'function') {
|
||||||
await client.initRustCrypto();
|
await client.initRustCrypto();
|
||||||
console.log('E2EE crypto initialized successfully');
|
log.info('E2EE crypto initialized successfully');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// This is expected in dev mode - WASM loading can be problematic
|
// This is expected in dev mode - WASM loading can be problematic
|
||||||
console.info('Crypto not available - encrypted rooms will show encrypted messages');
|
log.info('Crypto not available - encrypted rooms will show encrypted messages');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the client (begins sync loop)
|
// Start the client (begins sync loop)
|
||||||
@@ -204,7 +207,7 @@ export async function logout(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
await client.logout();
|
await client.logout();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error during logout:', e);
|
log.error('Error during logout', { error: e });
|
||||||
}
|
}
|
||||||
await stopClient();
|
await stopClient();
|
||||||
}
|
}
|
||||||
@@ -551,7 +554,7 @@ export async function setRoomNotificationLevel(roomId: string, level: Notificati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to set notification level:', e);
|
log.error('Failed to set notification level', { error: e });
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,7 +631,7 @@ export async function loadMoreMessages(roomId: string, limit = 50): Promise<{ ha
|
|||||||
|
|
||||||
return { hasMore, loaded };
|
return { hasMore, loaded };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load more messages:', e);
|
log.error('Failed to load more messages', { error: e });
|
||||||
return { hasMore: false, loaded: 0 };
|
return { hasMore: false, loaded: 0 };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,7 +700,7 @@ export async function sendFileMessage(
|
|||||||
content.info.w = dimensions.width;
|
content.info.w = dimensions.width;
|
||||||
content.info.h = dimensions.height;
|
content.info.h = dimensions.height;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to get image dimensions:', e);
|
log.warn('Failed to get image dimensions', { error: e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -782,7 +785,7 @@ export async function getAuthenticatedMediaUrl(mxcUrl: string): Promise<string |
|
|||||||
|
|
||||||
return blobUrl;
|
return blobUrl;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to fetch authenticated media:', e);
|
log.error('Failed to fetch authenticated media', { error: e });
|
||||||
// Fallback to unauthenticated URL
|
// Fallback to unauthenticated URL
|
||||||
return client.mxcUrlToHttp(mxcUrl);
|
return client.mxcUrlToHttp(mxcUrl);
|
||||||
}
|
}
|
||||||
@@ -834,7 +837,7 @@ export async function getAuthenticatedThumbnailUrl(
|
|||||||
|
|
||||||
return blobUrl;
|
return blobUrl;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to fetch authenticated thumbnail:', e);
|
log.error('Failed to fetch authenticated thumbnail', { error: e });
|
||||||
return client.mxcUrlToHttp(mxcUrl, width, height, 'scale');
|
return client.mxcUrlToHttp(mxcUrl, width, height, 'scale');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -936,7 +939,7 @@ export async function searchUsers(query: string, limit = 10): Promise<Array<{
|
|||||||
avatarUrl: user.avatar_url ? client!.mxcUrlToHttp(user.avatar_url, 40, 40, 'crop') : null,
|
avatarUrl: user.avatar_url ? client!.mxcUrlToHttp(user.avatar_url, 40, 40, 'crop') : null,
|
||||||
}));
|
}));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('User search failed:', e);
|
log.error('User search failed', { error: e });
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1080,7 +1083,7 @@ export async function setPresence(presence: 'online' | 'offline' | 'unavailable'
|
|||||||
try {
|
try {
|
||||||
await client.setPresence({ presence, status_msg: statusMsg });
|
await client.setPresence({ presence, status_msg: statusMsg });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to set presence:', e);
|
log.error('Failed to set presence', { error: e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ function loadTheme(): ThemeState {
|
|||||||
return { ...defaultTheme, ...JSON.parse(stored) };
|
return { ...defaultTheme, ...JSON.parse(stored) };
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to load theme:', e);
|
// Theme load failure is non-critical, fall through to default
|
||||||
}
|
}
|
||||||
return defaultTheme;
|
return defaultTheme;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,6 +195,19 @@ export function clearRecentLogs() {
|
|||||||
* Format recent logs as a copyable string for bug reports.
|
* Format recent logs as a copyable string for bug reports.
|
||||||
* User can paste this to you for debugging.
|
* User can paste this to you for debugging.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Safely extract an error message from an unknown caught value.
|
||||||
|
* Use in catch blocks: `catch (e: unknown) { toasts.error(getErrorMessage(e, 'fallback')) }`
|
||||||
|
*/
|
||||||
|
export function getErrorMessage(e: unknown, fallback = 'An unexpected error occurred'): string {
|
||||||
|
if (e instanceof Error) return e.message;
|
||||||
|
if (typeof e === 'string') return e;
|
||||||
|
if (e && typeof e === 'object' && 'message' in e && typeof (e as { message: unknown }).message === 'string') {
|
||||||
|
return (e as { message: string }).message;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
export function dumpLogs(): string {
|
export function dumpLogs(): string {
|
||||||
return recentLogs
|
return recentLogs
|
||||||
.map((e) => {
|
.map((e) => {
|
||||||
|
|||||||
@@ -45,6 +45,9 @@
|
|||||||
import { clearBlobUrlCache } from "$lib/cache/mediaCache";
|
import { clearBlobUrlCache } from "$lib/cache/mediaCache";
|
||||||
import type { Message } from "$lib/matrix/types";
|
import type { Message } from "$lib/matrix/types";
|
||||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
|
import { createLogger, getErrorMessage } from "$lib/utils/logger";
|
||||||
|
|
||||||
|
const log = createLogger('chat:page');
|
||||||
|
|
||||||
const supabase = getContext<SupabaseClient>("supabase");
|
const supabase = getContext<SupabaseClient>("supabase");
|
||||||
let data = $derived(page.data);
|
let data = $derived(page.data);
|
||||||
@@ -120,7 +123,7 @@
|
|||||||
await initCache();
|
await initCache();
|
||||||
await cleanupCache(7 * 24 * 60 * 60 * 1000);
|
await cleanupCache(7 * 24 * 60 * 60 * 1000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Cache initialization failed:", e);
|
log.warn('Cache initialization failed', { error: e });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load credentials from Supabase
|
// Try to load credentials from Supabase
|
||||||
@@ -141,7 +144,7 @@
|
|||||||
isInitializing = false;
|
isInitializing = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to load Matrix credentials:", e);
|
log.error('Failed to load Matrix credentials', { error: e });
|
||||||
showJoinScreen = true;
|
showJoinScreen = true;
|
||||||
isInitializing = false;
|
isInitializing = false;
|
||||||
}
|
}
|
||||||
@@ -164,7 +167,7 @@
|
|||||||
// Check if org has a Matrix Space, auto-create if not
|
// Check if org has a Matrix Space, auto-create if not
|
||||||
await ensureOrgSpace(credentials);
|
await ensureOrgSpace(credentials);
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to init Matrix client:", e);
|
log.error('Failed to init Matrix client', { error: e });
|
||||||
toasts.error(m.chat_join_error());
|
toasts.error(m.chat_join_error());
|
||||||
showJoinScreen = true;
|
showJoinScreen = true;
|
||||||
} finally {
|
} finally {
|
||||||
@@ -196,7 +199,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("Failed to ensure org space:", e);
|
log.warn('Failed to ensure org space', { error: e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,8 +226,8 @@
|
|||||||
if (result.provisioned) {
|
if (result.provisioned) {
|
||||||
toasts.success(m.chat_join_success());
|
toasts.success(m.chat_join_success());
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || m.chat_join_error());
|
toasts.error(getErrorMessage(e, m.chat_join_error()));
|
||||||
} finally {
|
} finally {
|
||||||
isProvisioning = false;
|
isProvisioning = false;
|
||||||
}
|
}
|
||||||
@@ -297,8 +300,8 @@
|
|||||||
await editMessage($selectedRoomId, editingMsg.eventId, newContent);
|
await editMessage($selectedRoomId, editingMsg.eventId, newContent);
|
||||||
editingMsg = null;
|
editingMsg = null;
|
||||||
toasts.success("Message edited");
|
toasts.success("Message edited");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to edit message");
|
toasts.error(getErrorMessage(e, 'Failed to edit message'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,8 +315,8 @@
|
|||||||
try {
|
try {
|
||||||
await deleteMessage($selectedRoomId, messageId);
|
await deleteMessage($selectedRoomId, messageId);
|
||||||
toasts.success("Message deleted");
|
toasts.success("Message deleted");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to delete message");
|
toasts.error(getErrorMessage(e, 'Failed to delete message'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +358,8 @@
|
|||||||
const contentUri = await uploadFile(file);
|
const contentUri = await uploadFile(file);
|
||||||
await sendFileMessage($selectedRoomId, file, contentUri);
|
await sendFileMessage($selectedRoomId, file, contentUri);
|
||||||
toasts.success("File sent!");
|
toasts.success("File sent!");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to upload file");
|
toasts.error(getErrorMessage(e, 'Failed to upload file'));
|
||||||
} finally {
|
} finally {
|
||||||
isUploadingDrop = false;
|
isUploadingDrop = false;
|
||||||
}
|
}
|
||||||
@@ -369,8 +372,8 @@
|
|||||||
const result = await loadMoreMessages($selectedRoomId);
|
const result = await loadMoreMessages($selectedRoomId);
|
||||||
loadRoomMessages($selectedRoomId);
|
loadRoomMessages($selectedRoomId);
|
||||||
if (!result.hasMore) toasts.info("No more messages to load");
|
if (!result.hasMore) toasts.info("No more messages to load");
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error("Failed to load more messages:", e);
|
log.error('Failed to load more messages', { error: e });
|
||||||
} finally {
|
} finally {
|
||||||
isLoadingMore = false;
|
isLoadingMore = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export const load: PageServerLoad = async ({ params, locals, url }) => {
|
|||||||
try {
|
try {
|
||||||
const events = await fetchEvents(locals.supabase, org.id, statusFilter);
|
const events = await fetchEvents(locals.supabase, org.id, statusFilter);
|
||||||
return { events, statusFilter };
|
return { events, statusFilter };
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
log.error('Failed to load events', { error: e, data: { orgId: org.id } });
|
log.error('Failed to load events', { error: e, data: { orgId: org.id } });
|
||||||
return { events: [], statusFilter };
|
return { events: [], statusFilter };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
import type { Database } from "$lib/supabase/types";
|
import type { Database } from "$lib/supabase/types";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { getErrorMessage } from "$lib/utils/logger";
|
||||||
import * as m from "$lib/paraglide/messages";
|
import * as m from "$lib/paraglide/messages";
|
||||||
|
|
||||||
interface EventItem {
|
interface EventItem {
|
||||||
@@ -100,8 +101,8 @@
|
|||||||
showCreateModal = false;
|
showCreateModal = false;
|
||||||
resetForm();
|
resetForm();
|
||||||
goto(`/${data.org.slug}/events/${created.slug}`);
|
goto(`/${data.org.slug}/events/${created.slug}`);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to create event");
|
toasts.error(getErrorMessage(e, 'Failed to create event'));
|
||||||
} finally {
|
} finally {
|
||||||
creating = false;
|
creating = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ export const load: LayoutServerLoad = async ({ params, locals, parent }) => {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
return { event, eventMembers: members, eventRoles: roles, eventDepartments: departments };
|
return { event, eventMembers: members, eventRoles: roles, eventDepartments: departments };
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
if (e?.status === 404) throw e;
|
if (e && typeof e === 'object' && 'status' in e && (e as { status: number }).status === 404) throw e;
|
||||||
log.error('Failed to load event', { error: e, data: { orgId, eventSlug: params.eventSlug } });
|
log.error('Failed to load event', { error: e, data: { orgId, eventSlug: params.eventSlug } });
|
||||||
error(500, 'Failed to load event');
|
error(500, 'Failed to load event');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
import type { Database } from "$lib/supabase/types";
|
import type { Database } from "$lib/supabase/types";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { getErrorMessage } from "$lib/utils/logger";
|
||||||
import type { Event, EventMemberWithDetails, EventRole, EventDepartment } from "$lib/api/events";
|
import type { Event, EventMemberWithDetails, EventRole, EventDepartment } from "$lib/api/events";
|
||||||
import * as m from "$lib/paraglide/messages";
|
import * as m from "$lib/paraglide/messages";
|
||||||
|
|
||||||
@@ -173,8 +174,8 @@
|
|||||||
goto(`/${data.org.slug}/events/${data.event.slug}`, {
|
goto(`/${data.org.slug}/events/${data.event.slug}`, {
|
||||||
invalidateAll: true,
|
invalidateAll: true,
|
||||||
});
|
});
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to update event");
|
toasts.error(getErrorMessage(e, 'Failed to update event'));
|
||||||
} finally {
|
} finally {
|
||||||
saving = false;
|
saving = false;
|
||||||
}
|
}
|
||||||
@@ -192,8 +193,8 @@
|
|||||||
|
|
||||||
toasts.success(m.events_deleted());
|
toasts.success(m.events_deleted());
|
||||||
goto(`/${data.org.slug}/events`);
|
goto(`/${data.org.slug}/events`);
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to delete event");
|
toasts.error(getErrorMessage(e, 'Failed to delete event'));
|
||||||
} finally {
|
} finally {
|
||||||
deleting = false;
|
deleting = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const load: PageServerLoad = async ({ params, locals, parent }) => {
|
|||||||
sponsors,
|
sponsors,
|
||||||
sponsorDeliverables,
|
sponsorDeliverables,
|
||||||
};
|
};
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
log.error('Failed to load department dashboard', { error: e, data: { deptId: params.deptId } });
|
log.error('Failed to load department dashboard', { error: e, data: { deptId: params.deptId } });
|
||||||
error(500, 'Failed to load department dashboard');
|
error(500, 'Failed to load department dashboard');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import type { SupabaseClient } from "@supabase/supabase-js";
|
import type { SupabaseClient } from "@supabase/supabase-js";
|
||||||
import type { Database } from "$lib/supabase/types";
|
import type { Database } from "$lib/supabase/types";
|
||||||
import { toasts } from "$lib/stores/ui";
|
import { toasts } from "$lib/stores/ui";
|
||||||
|
import { getErrorMessage } from "$lib/utils/logger";
|
||||||
import type {
|
import type {
|
||||||
Event,
|
Event,
|
||||||
EventMemberWithDetails,
|
EventMemberWithDetails,
|
||||||
@@ -260,8 +261,8 @@
|
|||||||
selectedRoleId = "";
|
selectedRoleId = "";
|
||||||
selectedDeptIds = [];
|
selectedDeptIds = [];
|
||||||
addNotes = "";
|
addNotes = "";
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to add member");
|
toasts.error(getErrorMessage(e, 'Failed to add member'));
|
||||||
} finally {
|
} finally {
|
||||||
adding = false;
|
adding = false;
|
||||||
}
|
}
|
||||||
@@ -327,8 +328,8 @@
|
|||||||
|
|
||||||
toasts.success(m.team_updated());
|
toasts.success(m.team_updated());
|
||||||
editingMember = null;
|
editingMember = null;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to update member");
|
toasts.error(getErrorMessage(e, 'Failed to update member'));
|
||||||
} finally {
|
} finally {
|
||||||
updatingMember = false;
|
updatingMember = false;
|
||||||
}
|
}
|
||||||
@@ -349,8 +350,8 @@
|
|||||||
teamMembers = teamMembers.filter((tm) => tm.id !== memberToRemove!.id);
|
teamMembers = teamMembers.filter((tm) => tm.id !== memberToRemove!.id);
|
||||||
toasts.success(m.team_removed({ name }));
|
toasts.success(m.team_removed({ name }));
|
||||||
memberToRemove = null;
|
memberToRemove = null;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to remove member");
|
toasts.error(getErrorMessage(e, 'Failed to remove member'));
|
||||||
} finally {
|
} finally {
|
||||||
removing = false;
|
removing = false;
|
||||||
}
|
}
|
||||||
@@ -398,8 +399,8 @@
|
|||||||
toasts.success(m.team_dept_created());
|
toasts.success(m.team_dept_created());
|
||||||
}
|
}
|
||||||
showDeptModal = false;
|
showDeptModal = false;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to save department");
|
toasts.error(getErrorMessage(e, 'Failed to save department'));
|
||||||
} finally {
|
} finally {
|
||||||
savingDept = false;
|
savingDept = false;
|
||||||
}
|
}
|
||||||
@@ -419,8 +420,8 @@
|
|||||||
departments: tm.departments.filter((d) => d.id !== dept.id),
|
departments: tm.departments.filter((d) => d.id !== dept.id),
|
||||||
}));
|
}));
|
||||||
toasts.success(m.team_dept_deleted());
|
toasts.success(m.team_dept_deleted());
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to delete department");
|
toasts.error(getErrorMessage(e, 'Failed to delete department'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,8 +465,8 @@
|
|||||||
toasts.success(m.team_role_created());
|
toasts.success(m.team_role_created());
|
||||||
}
|
}
|
||||||
showRoleModal = false;
|
showRoleModal = false;
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to save role");
|
toasts.error(getErrorMessage(e, 'Failed to save role'));
|
||||||
} finally {
|
} finally {
|
||||||
savingRole = false;
|
savingRole = false;
|
||||||
}
|
}
|
||||||
@@ -486,8 +487,8 @@
|
|||||||
: tm,
|
: tm,
|
||||||
);
|
);
|
||||||
toasts.success(m.team_role_deleted());
|
toasts.success(m.team_role_deleted());
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
toasts.error(e.message || "Failed to delete role");
|
toasts.error(getErrorMessage(e, 'Failed to delete role'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -621,8 +621,9 @@
|
|||||||
<Input label="Name" name="name" bind:value={editEventModal.name} />
|
<Input label="Name" name="name" bind:value={editEventModal.name} />
|
||||||
<Input label="Slug" name="slug" bind:value={editEventModal.slug} />
|
<Input label="Slug" name="slug" bind:value={editEventModal.slug} />
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-body-sm text-light/60 mb-1">Status</label>
|
<label for="event-status" class="block text-body-sm text-light/60 mb-1">Status</label>
|
||||||
<select
|
<select
|
||||||
|
id="event-status"
|
||||||
name="status"
|
name="status"
|
||||||
bind:value={editEventModal.status}
|
bind:value={editEventModal.status}
|
||||||
class="w-full bg-dark/50 border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white focus:outline-none focus:border-primary/50"
|
class="w-full bg-dark/50 border border-light/10 rounded-xl px-3 py-2 text-body-sm text-white focus:outline-none focus:border-primary/50"
|
||||||
@@ -634,8 +635,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-2 gap-3">
|
<div class="grid grid-cols-2 gap-3">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-body-sm text-light/60 mb-1">Start Date</label>
|
<label for="event-start-date" class="block text-body-sm text-light/60 mb-1">Start Date</label>
|
||||||
<input
|
<input
|
||||||
|
id="event-start-date"
|
||||||
type="date"
|
type="date"
|
||||||
name="start_date"
|
name="start_date"
|
||||||
bind:value={editEventModal.start_date}
|
bind:value={editEventModal.start_date}
|
||||||
@@ -643,8 +645,9 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-body-sm text-light/60 mb-1">End Date</label>
|
<label for="event-end-date" class="block text-body-sm text-light/60 mb-1">End Date</label>
|
||||||
<input
|
<input
|
||||||
|
id="event-end-date"
|
||||||
type="date"
|
type="date"
|
||||||
name="end_date"
|
name="end_date"
|
||||||
bind:value={editEventModal.end_date}
|
bind:value={editEventModal.end_date}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { json } from '@sveltejs/kit';
|
import { json } from '@sveltejs/kit';
|
||||||
import { env } from '$env/dynamic/private';
|
import { env } from '$env/dynamic/private';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
import { createLogger } from '$lib/utils/logger';
|
||||||
|
|
||||||
|
const log = createLogger('api:matrix-provision');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/matrix-provision
|
* POST /api/matrix-provision
|
||||||
@@ -83,7 +86,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
|
|
||||||
if (!registerRes.ok) {
|
if (!registerRes.ok) {
|
||||||
const err = await registerRes.json().catch(() => ({}));
|
const err = await registerRes.json().catch(() => ({}));
|
||||||
console.error('Matrix register failed:', registerRes.status, err);
|
log.error('Matrix register failed', { data: { status: registerRes.status }, error: err });
|
||||||
return json({ error: 'Failed to create Matrix account' }, { status: 500 });
|
return json({ error: 'Failed to create Matrix account' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +107,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
|
|
||||||
if (!loginRes.ok) {
|
if (!loginRes.ok) {
|
||||||
const err = await loginRes.json().catch(() => ({}));
|
const err = await loginRes.json().catch(() => ({}));
|
||||||
console.error('Matrix login failed:', loginRes.status, err);
|
log.error('Matrix login failed', { data: { status: loginRes.status }, error: err });
|
||||||
return json({ error: 'Failed to login to Matrix account' }, { status: 500 });
|
return json({ error: 'Failed to login to Matrix account' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +121,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
try {
|
try {
|
||||||
await setMatrixAvatar(homeserverUrl, accessToken, profile.avatar_url);
|
await setMatrixAvatar(homeserverUrl, accessToken, profile.avatar_url);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Failed to set Matrix avatar:', e);
|
log.warn('Failed to set Matrix avatar', { error: e });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +141,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (upsertError) {
|
if (upsertError) {
|
||||||
console.error('Failed to store Matrix credentials:', upsertError);
|
log.error('Failed to store Matrix credentials', { error: upsertError });
|
||||||
return json({ error: 'Failed to store credentials' }, { status: 500 });
|
return json({ error: 'Failed to store credentials' }, { status: 500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +155,7 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
provisioned: true,
|
provisioned: true,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Matrix provisioning error:', e);
|
log.error('Matrix provisioning error', { error: e });
|
||||||
return json({ error: 'Matrix provisioning failed' }, { status: 500 });
|
return json({ error: 'Matrix provisioning failed' }, { status: 500 });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { json } from '@sveltejs/kit';
|
import { json } from '@sveltejs/kit';
|
||||||
import type { RequestHandler } from './$types';
|
import type { RequestHandler } from './$types';
|
||||||
|
import { createLogger, getErrorMessage } from '$lib/utils/logger';
|
||||||
|
|
||||||
|
const log = createLogger('api:matrix-space');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET: Retrieve the Matrix Space ID for an org
|
* GET: Retrieve the Matrix Space ID for an org
|
||||||
@@ -140,9 +143,9 @@ export const POST: RequestHandler = async ({ request, locals }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return json({ spaceId, created: true });
|
return json({ spaceId, created: true });
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
console.error('Failed to create Matrix Space:', e);
|
log.error('Failed to create Matrix Space', { error: e });
|
||||||
return json({ error: e.message || 'Failed to create Matrix Space' }, { status: 500 });
|
return json({ error: getErrorMessage(e, 'Failed to create Matrix Space') }, { status: 500 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user