From ab8743bdae48d2d3e9808541b051c77e7e908bdb Mon Sep 17 00:00:00 2001 From: jarek Date: Mon, 29 Dec 2025 08:40:11 +0100 Subject: [PATCH] proper src structure, dockerfile, entrypoint --- Dockerfile | 86 ++ bunfig.toml | 9 + components.json | 16 + docker-entrypoint.sh | 122 +++ drizzle.config.ts | 16 + package.json | 110 ++ app.css => src/app.css | 0 app.d.ts => src/app.d.ts | 0 app.html => src/app.html | 0 hooks.server.ts => src/hooks.server.ts | 0 {images => src/images}/logo.webp | Bin {lib => src/lib}/actions/column-resize.ts | 0 {lib => src/lib}/assets/favicon.svg | 0 .../lib}/components/AvatarCropper.svelte | 0 .../components/BatchOperationModal.svelte | 0 {lib => src/lib}/components/CodeEditor.svelte | 0 .../components/ColumnSettingsPopover.svelte | 0 .../lib}/components/CommandPalette.svelte | 0 .../lib}/components/ConfirmPopover.svelte | 0 .../lib}/components/ExecutionLogViewer.svelte | 0 .../lib}/components/MultiSelectFilter.svelte | 0 {lib => src/lib}/components/PageHeader.svelte | 0 .../PasswordStrengthIndicator.svelte | 0 {lib => src/lib}/components/PullTab.svelte | 0 {lib => src/lib}/components/PushTab.svelte | 0 {lib => src/lib}/components/ScanTab.svelte | 0 .../components/ScannerSeverityPills.svelte | 0 {lib => src/lib}/components/Sidebar.svelte | 0 .../lib}/components/StackEnvVarsEditor.svelte | 0 .../lib}/components/StackEnvVarsPanel.svelte | 0 .../lib}/components/ThemeSelector.svelte | 0 .../lib}/components/TimezoneSelector.svelte | 0 .../lib}/components/UpdateContainerRow.svelte | 0 .../components/UpdateStepIndicator.svelte | 0 .../lib}/components/UpdateSummaryStats.svelte | 0 .../VulnerabilityCriteriaBadge.svelte | 0 .../VulnerabilityCriteriaSelector.svelte | 0 .../lib}/components/WhatsNewModal.svelte | 0 .../lib}/components/app-sidebar.svelte | 0 .../lib}/components/cron-editor.svelte | 0 .../lib}/components/data-grid/DataGrid.svelte | 0 .../lib}/components/data-grid/context.ts | 0 .../lib}/components/data-grid/index.ts | 0 .../lib}/components/data-grid/types.ts | 0 {lib => src/lib}/components/host-info.svelte | 0 .../lib}/components/icon-picker.svelte | 0 .../lib}/components/main-content.svelte | 0 .../lib}/components/permission-guard.svelte | 0 .../lib}/components/theme-toggle.svelte | 0 .../ui/accordion/accordion-content.svelte | 0 .../ui/accordion/accordion-item.svelte | 0 .../ui/accordion/accordion-trigger.svelte | 0 .../components/ui/accordion/accordion.svelte | 0 .../lib}/components/ui/accordion/index.ts | 0 .../ui/alert/alert-description.svelte | 0 .../components/ui/alert/alert-title.svelte | 0 .../lib}/components/ui/alert/alert.svelte | 0 {lib => src/lib}/components/ui/alert/index.ts | 0 .../ui/avatar/avatar-fallback.svelte | 0 .../components/ui/avatar/avatar-image.svelte | 0 .../lib}/components/ui/avatar/avatar.svelte | 0 .../lib}/components/ui/avatar/index.ts | 0 .../lib}/components/ui/badge/badge.svelte | 0 {lib => src/lib}/components/ui/badge/index.ts | 0 .../lib}/components/ui/button/button.svelte | 0 .../lib}/components/ui/button/index.ts | 0 .../ui/calendar/calendar-caption.svelte | 0 .../ui/calendar/calendar-cell.svelte | 0 .../ui/calendar/calendar-day.svelte | 0 .../ui/calendar/calendar-grid-body.svelte | 0 .../ui/calendar/calendar-grid-head.svelte | 0 .../ui/calendar/calendar-grid-row.svelte | 0 .../ui/calendar/calendar-grid.svelte | 0 .../ui/calendar/calendar-head-cell.svelte | 0 .../ui/calendar/calendar-header.svelte | 0 .../ui/calendar/calendar-heading.svelte | 0 .../ui/calendar/calendar-month-select.svelte | 0 .../ui/calendar/calendar-month.svelte | 0 .../ui/calendar/calendar-months.svelte | 0 .../ui/calendar/calendar-nav.svelte | 0 .../ui/calendar/calendar-next-button.svelte | 0 .../ui/calendar/calendar-prev-button.svelte | 0 .../ui/calendar/calendar-year-select.svelte | 0 .../components/ui/calendar/calendar.svelte | 0 .../lib}/components/ui/calendar/index.ts | 0 .../components/ui/card/card-action.svelte | 0 .../components/ui/card/card-content.svelte | 0 .../ui/card/card-description.svelte | 0 .../components/ui/card/card-footer.svelte | 0 .../components/ui/card/card-header.svelte | 0 .../lib}/components/ui/card/card-title.svelte | 0 .../lib}/components/ui/card/card.svelte | 0 {lib => src/lib}/components/ui/card/index.ts | 0 .../components/ui/checkbox/checkbox.svelte | 0 .../lib}/components/ui/checkbox/index.ts | 0 .../ui/command/command-dialog.svelte | 0 .../ui/command/command-empty.svelte | 0 .../ui/command/command-group.svelte | 0 .../ui/command/command-input.svelte | 0 .../components/ui/command/command-item.svelte | 0 .../ui/command/command-link-item.svelte | 0 .../components/ui/command/command-list.svelte | 0 .../ui/command/command-loading.svelte | 0 .../ui/command/command-separator.svelte | 0 .../ui/command/command-shortcut.svelte | 0 .../lib}/components/ui/command/command.svelte | 0 .../lib}/components/ui/command/index.ts | 0 .../ui/date-picker/date-picker.svelte | 0 .../lib}/components/ui/date-picker/index.ts | 0 .../components/ui/dialog/dialog-close.svelte | 0 .../ui/dialog/dialog-content.svelte | 0 .../ui/dialog/dialog-description.svelte | 0 .../components/ui/dialog/dialog-footer.svelte | 0 .../components/ui/dialog/dialog-header.svelte | 0 .../ui/dialog/dialog-overlay.svelte | 0 .../components/ui/dialog/dialog-portal.svelte | 0 .../components/ui/dialog/dialog-title.svelte | 0 .../ui/dialog/dialog-trigger.svelte | 0 .../lib}/components/ui/dialog/dialog.svelte | 0 .../lib}/components/ui/dialog/index.ts | 0 .../dropdown-menu-checkbox-group.svelte | 0 .../dropdown-menu-checkbox-item.svelte | 0 .../dropdown-menu-content.svelte | 0 .../dropdown-menu-group-heading.svelte | 0 .../dropdown-menu/dropdown-menu-group.svelte | 0 .../dropdown-menu/dropdown-menu-item.svelte | 0 .../dropdown-menu/dropdown-menu-label.svelte | 0 .../dropdown-menu/dropdown-menu-portal.svelte | 0 .../dropdown-menu-radio-group.svelte | 0 .../dropdown-menu-radio-item.svelte | 0 .../dropdown-menu-separator.svelte | 0 .../dropdown-menu-shortcut.svelte | 0 .../dropdown-menu-sub-content.svelte | 0 .../dropdown-menu-sub-trigger.svelte | 0 .../ui/dropdown-menu/dropdown-menu-sub.svelte | 0 .../dropdown-menu-trigger.svelte | 0 .../ui/dropdown-menu/dropdown-menu.svelte | 0 .../lib}/components/ui/dropdown-menu/index.ts | 0 .../ui/empty-state/empty-state.svelte | 0 .../lib}/components/ui/empty-state/index.ts | 0 .../ui/empty-state/no-environment.svelte | 0 {lib => src/lib}/components/ui/input/index.ts | 0 .../lib}/components/ui/input/input.svelte | 0 {lib => src/lib}/components/ui/label/index.ts | 0 .../lib}/components/ui/label/label.svelte | 0 .../lib}/components/ui/popover/index.ts | 0 .../ui/popover/popover-content.svelte | 0 .../ui/popover/popover-trigger.svelte | 0 .../lib}/components/ui/progress/index.ts | 0 .../components/ui/progress/progress.svelte | 0 .../lib}/components/ui/select/index.ts | 0 .../ui/select/select-content.svelte | 0 .../ui/select/select-group-heading.svelte | 0 .../components/ui/select/select-group.svelte | 0 .../components/ui/select/select-item.svelte | 0 .../components/ui/select/select-label.svelte | 0 .../select/select-scroll-down-button.svelte | 0 .../ui/select/select-scroll-up-button.svelte | 0 .../ui/select/select-separator.svelte | 0 .../ui/select/select-trigger.svelte | 0 .../lib}/components/ui/separator/index.ts | 0 .../components/ui/separator/separator.svelte | 0 {lib => src/lib}/components/ui/sheet/index.ts | 0 .../components/ui/sheet/sheet-close.svelte | 0 .../components/ui/sheet/sheet-content.svelte | 0 .../ui/sheet/sheet-description.svelte | 0 .../components/ui/sheet/sheet-footer.svelte | 0 .../components/ui/sheet/sheet-header.svelte | 0 .../components/ui/sheet/sheet-overlay.svelte | 0 .../components/ui/sheet/sheet-title.svelte | 0 .../components/ui/sheet/sheet-trigger.svelte | 0 .../lib}/components/ui/sidebar/constants.ts | 0 .../components/ui/sidebar/context.svelte.ts | 0 .../lib}/components/ui/sidebar/index.ts | 0 .../ui/sidebar/sidebar-content.svelte | 0 .../ui/sidebar/sidebar-footer.svelte | 0 .../ui/sidebar/sidebar-group-action.svelte | 0 .../ui/sidebar/sidebar-group-content.svelte | 0 .../ui/sidebar/sidebar-group-label.svelte | 0 .../ui/sidebar/sidebar-group.svelte | 0 .../ui/sidebar/sidebar-header.svelte | 0 .../ui/sidebar/sidebar-input.svelte | 0 .../ui/sidebar/sidebar-inset.svelte | 0 .../ui/sidebar/sidebar-menu-action.svelte | 0 .../ui/sidebar/sidebar-menu-badge.svelte | 0 .../ui/sidebar/sidebar-menu-button.svelte | 0 .../ui/sidebar/sidebar-menu-item.svelte | 0 .../ui/sidebar/sidebar-menu-skeleton.svelte | 0 .../ui/sidebar/sidebar-menu-sub-button.svelte | 0 .../ui/sidebar/sidebar-menu-sub-item.svelte | 0 .../ui/sidebar/sidebar-menu-sub.svelte | 0 .../components/ui/sidebar/sidebar-menu.svelte | 0 .../ui/sidebar/sidebar-provider.svelte | 0 .../components/ui/sidebar/sidebar-rail.svelte | 0 .../ui/sidebar/sidebar-separator.svelte | 0 .../ui/sidebar/sidebar-trigger.svelte | 0 .../lib}/components/ui/sidebar/sidebar.svelte | 0 .../lib}/components/ui/skeleton/index.ts | 0 .../components/ui/skeleton/skeleton.svelte | 0 .../lib}/components/ui/sonner/index.ts | 0 .../lib}/components/ui/sonner/sonner.svelte | 0 .../lib}/components/ui/switch/index.ts | 0 .../lib}/components/ui/switch/switch.svelte | 0 {lib => src/lib}/components/ui/table/index.ts | 0 .../components/ui/table/table-body.svelte | 0 .../components/ui/table/table-caption.svelte | 0 .../components/ui/table/table-cell.svelte | 0 .../components/ui/table/table-footer.svelte | 0 .../components/ui/table/table-head.svelte | 0 .../components/ui/table/table-header.svelte | 0 .../lib}/components/ui/table/table-row.svelte | 0 .../lib}/components/ui/table/table.svelte | 0 {lib => src/lib}/components/ui/tabs/index.ts | 0 .../components/ui/tabs/tabs-content.svelte | 0 .../lib}/components/ui/tabs/tabs-list.svelte | 0 .../components/ui/tabs/tabs-trigger.svelte | 0 .../lib}/components/ui/tabs/tabs.svelte | 0 .../lib}/components/ui/textarea/index.ts | 0 .../components/ui/textarea/textarea.svelte | 0 .../lib}/components/ui/toggle-pill/index.ts | 0 .../ui/toggle-pill/toggle-group.svelte | 0 .../ui/toggle-pill/toggle-pill.svelte | 0 .../ui/toggle-pill/toggle-switch.svelte | 0 .../lib}/components/ui/tooltip/index.ts | 0 .../ui/tooltip/tooltip-content.svelte | 0 .../ui/tooltip/tooltip-trigger.svelte | 0 {lib => src/lib}/config/grid-columns.ts | 0 {lib => src/lib}/data/changelog.json | 0 {lib => src/lib}/data/dependencies.json | 0 {lib => src/lib}/hooks/is-mobile.svelte.ts | 0 {lib => src/lib}/index.ts | 0 {lib => src/lib}/server/audit-events.ts | 0 {lib => src/lib}/server/audit.ts | 0 {lib => src/lib}/server/auth.ts | 0 {lib => src/lib}/server/authorize.ts | 0 {lib => src/lib}/server/db.ts | 0 {lib => src/lib}/server/db/connection.ts | 0 {lib => src/lib}/server/db/drizzle.ts | 0 {lib => src/lib}/server/db/schema/index.ts | 0 .../lib}/server/db/schema/pg-schema.ts | 0 {lib => src/lib}/server/docker.ts | 0 {lib => src/lib}/server/event-collector.ts | 0 {lib => src/lib}/server/git.ts | 0 {lib => src/lib}/server/hawser.ts | 0 {lib => src/lib}/server/license.ts | 0 {lib => src/lib}/server/metrics-collector.ts | 0 {lib => src/lib}/server/notifications.ts | 0 {lib => src/lib}/server/scanner.ts | 0 {lib => src/lib}/server/scheduler/index.ts | 0 .../scheduler/tasks/container-update.ts | 0 .../scheduler/tasks/env-update-check.ts | 0 .../server/scheduler/tasks/git-stack-sync.ts | 0 .../server/scheduler/tasks/system-cleanup.ts | 0 .../server/scheduler/tasks/update-utils.ts | 0 {lib => src/lib}/server/stacks.ts | 0 {lib => src/lib}/server/subprocess-manager.ts | 0 .../server/subprocesses/event-subprocess.ts | 0 .../server/subprocesses/metrics-subprocess.ts | 0 {lib => src/lib}/server/uptime.ts | 0 {lib => src/lib}/stores/audit-events.ts | 0 {lib => src/lib}/stores/auth.ts | 0 {lib => src/lib}/stores/dashboard.ts | 0 {lib => src/lib}/stores/environment.ts | 0 {lib => src/lib}/stores/events.ts | 0 {lib => src/lib}/stores/grid-preferences.ts | 0 {lib => src/lib}/stores/license.ts | 0 {lib => src/lib}/stores/settings.ts | 0 {lib => src/lib}/stores/stats.ts | 0 {lib => src/lib}/stores/theme.ts | 0 {lib => src/lib}/themes.ts | 0 {lib => src/lib}/types.ts | 0 {lib => src/lib}/utils.ts | 0 {lib => src/lib}/utils/icons.ts | 0 {lib => src/lib}/utils/ip.ts | 0 {lib => src/lib}/utils/label-colors.ts | 0 {lib => src/lib}/utils/update-steps.ts | 0 {lib => src/lib}/utils/version.ts | 0 {routes => src/routes}/+layout.server.ts | 0 {routes => src/routes}/+layout.svelte | 0 {routes => src/routes}/+layout.ts | 0 {routes => src/routes}/+page.svelte | 0 {routes => src/routes}/activity/+page.svelte | 0 {routes => src/routes}/alerts/+page.svelte | 0 .../routes}/api/activity/+server.ts | 0 .../api/activity/containers/+server.ts | 0 .../routes}/api/activity/events/+server.ts | 0 .../routes}/api/activity/stats/+server.ts | 0 {routes => src/routes}/api/audit/+server.ts | 0 .../routes}/api/audit/events/+server.ts | 0 .../routes}/api/audit/export/+server.ts | 0 .../routes}/api/audit/users/+server.ts | 0 .../routes}/api/auth/ldap/+server.ts | 0 .../routes}/api/auth/ldap/[id]/+server.ts | 0 .../api/auth/ldap/[id]/test/+server.ts | 0 .../routes}/api/auth/login/+server.ts | 0 .../routes}/api/auth/logout/+server.ts | 0 .../routes}/api/auth/oidc/+server.ts | 0 .../routes}/api/auth/oidc/[id]/+server.ts | 0 .../api/auth/oidc/[id]/initiate/+server.ts | 0 .../api/auth/oidc/[id]/test/+server.ts | 0 .../routes}/api/auth/oidc/callback/+server.ts | 0 .../routes}/api/auth/providers/+server.ts | 0 .../routes}/api/auth/session/+server.ts | 0 .../routes}/api/auth/settings/+server.ts | 0 .../routes}/api/auto-update/+server.ts | 0 .../auto-update/[containerName]/+server.ts | 0 {routes => src/routes}/api/batch/+server.ts | 0 .../routes}/api/changelog/+server.ts | 0 .../routes}/api/config-sets/+server.ts | 0 .../routes}/api/config-sets/[id]/+server.ts | 0 .../routes}/api/containers/+server.ts | 0 .../routes}/api/containers/[id]/+server.ts | 0 .../api/containers/[id]/exec/+server.ts | 0 .../api/containers/[id]/files/+server.ts | 0 .../containers/[id]/files/chmod/+server.ts | 0 .../containers/[id]/files/content/+server.ts | 0 .../containers/[id]/files/create/+server.ts | 0 .../containers/[id]/files/delete/+server.ts | 0 .../containers/[id]/files/download/+server.ts | 0 .../containers/[id]/files/rename/+server.ts | 0 .../containers/[id]/files/upload/+server.ts | 0 .../api/containers/[id]/inspect/+server.ts | 0 .../api/containers/[id]/logs/+server.ts | 0 .../containers/[id]/logs/stream/+server.ts | 0 .../api/containers/[id]/pause/+server.ts | 0 .../api/containers/[id]/rename/+server.ts | 0 .../api/containers/[id]/restart/+server.ts | 0 .../api/containers/[id]/start/+server.ts | 0 .../api/containers/[id]/stats/+server.ts | 0 .../api/containers/[id]/stop/+server.ts | 0 .../api/containers/[id]/top/+server.ts | 0 .../api/containers/[id]/unpause/+server.ts | 0 .../api/containers/[id]/update/+server.ts | 0 .../containers/batch-update-stream/+server.ts | 0 .../api/containers/batch-update/+server.ts | 0 .../api/containers/check-updates/+server.ts | 0 .../api/containers/pending-updates/+server.ts | 0 .../routes}/api/containers/sizes/+server.ts | 0 .../routes}/api/containers/stats/+server.ts | 0 .../api/dashboard/preferences/+server.ts | 0 .../routes}/api/dashboard/stats/+server.ts | 0 .../api/dashboard/stats/stream/+server.ts | 0 .../routes}/api/dependencies/+server.ts | 0 .../routes}/api/environments/+server.ts | 0 .../routes}/api/environments/[id]/+server.ts | 0 .../[id]/notifications/+server.ts | 0 .../notifications/[notificationId]/+server.ts | 0 .../api/environments/[id]/test/+server.ts | 0 .../api/environments/[id]/timezone/+server.ts | 0 .../environments/[id]/update-check/+server.ts | 0 .../api/environments/detect-socket/+server.ts | 0 .../routes}/api/environments/test/+server.ts | 0 {routes => src/routes}/api/events/+server.ts | 0 .../routes}/api/git/credentials/+server.ts | 0 .../api/git/credentials/[id]/+server.ts | 0 .../routes}/api/git/repositories/+server.ts | 0 .../api/git/repositories/[id]/+server.ts | 0 .../git/repositories/[id]/deploy/+server.ts | 0 .../api/git/repositories/[id]/sync/+server.ts | 0 .../api/git/repositories/[id]/test/+server.ts | 0 .../api/git/repositories/test/+server.ts | 0 .../routes}/api/git/stacks/+server.ts | 0 .../routes}/api/git/stacks/[id]/+server.ts | 0 .../git/stacks/[id]/deploy-stream/+server.ts | 0 .../api/git/stacks/[id]/deploy/+server.ts | 0 .../api/git/stacks/[id]/env-files/+server.ts | 0 .../api/git/stacks/[id]/sync/+server.ts | 0 .../api/git/stacks/[id]/test/+server.ts | 0 .../api/git/stacks/[id]/webhook/+server.ts | 0 .../routes}/api/git/webhook/[id]/+server.ts | 0 .../routes}/api/hawser/connect/+server.ts | 0 .../routes}/api/hawser/tokens/+server.ts | 0 {routes => src/routes}/api/health/+server.ts | 0 .../routes}/api/health/database/+server.ts | 0 {routes => src/routes}/api/host/+server.ts | 0 {routes => src/routes}/api/images/+server.ts | 0 .../routes}/api/images/[id]/+server.ts | 0 .../routes}/api/images/[id]/export/+server.ts | 0 .../api/images/[id]/history/+server.ts | 0 .../routes}/api/images/[id]/tag/+server.ts | 0 .../routes}/api/images/pull/+server.ts | 0 .../routes}/api/images/push/+server.ts | 0 .../routes}/api/images/scan/+server.ts | 0 .../routes}/api/legal/license/+server.ts | 0 .../routes}/api/legal/privacy/+server.ts | 0 {routes => src/routes}/api/license/+server.ts | 0 .../routes}/api/logs/merged/+server.ts | 0 {routes => src/routes}/api/metrics/+server.ts | 0 .../routes}/api/networks/+server.ts | 0 .../routes}/api/networks/[id]/+server.ts | 0 .../api/networks/[id]/connect/+server.ts | 0 .../api/networks/[id]/disconnect/+server.ts | 0 .../api/networks/[id]/inspect/+server.ts | 0 .../routes}/api/notifications/+server.ts | 0 .../routes}/api/notifications/[id]/+server.ts | 0 .../api/notifications/[id]/test/+server.ts | 0 .../routes}/api/notifications/test/+server.ts | 0 .../api/notifications/trigger-test/+server.ts | 0 .../preferences/favorite-groups/+server.ts | 0 .../api/preferences/favorites/+server.ts | 0 .../routes}/api/preferences/grid/+server.ts | 0 {routes => src/routes}/api/profile/+server.ts | 0 .../routes}/api/profile/avatar/+server.ts | 0 .../api/profile/preferences/+server.ts | 0 .../routes}/api/prune/all/+server.ts | 0 .../routes}/api/prune/containers/+server.ts | 0 .../routes}/api/prune/images/+server.ts | 0 .../routes}/api/prune/networks/+server.ts | 0 .../routes}/api/prune/volumes/+server.ts | 0 .../routes}/api/registries/+server.ts | 0 .../routes}/api/registries/[id]/+server.ts | 0 .../api/registries/[id]/default/+server.ts | 0 .../routes}/api/registry/catalog/+server.ts | 0 .../routes}/api/registry/image/+server.ts | 0 .../routes}/api/registry/search/+server.ts | 0 .../routes}/api/registry/tags/+server.ts | 0 {routes => src/routes}/api/roles/+server.ts | 0 .../routes}/api/roles/[id]/+server.ts | 0 .../routes}/api/schedules/+server.ts | 0 .../api/schedules/[type]/[id]/+server.ts | 0 .../api/schedules/[type]/[id]/run/+server.ts | 0 .../schedules/[type]/[id]/toggle/+server.ts | 0 .../api/schedules/executions/+server.ts | 0 .../api/schedules/executions/[id]/+server.ts | 0 .../routes}/api/schedules/settings/+server.ts | 0 .../routes}/api/schedules/stream/+server.ts | 0 .../schedules/system/[id]/toggle/+server.ts | 0 .../routes}/api/settings/general/+server.ts | 0 .../routes}/api/settings/scanner/+server.ts | 0 {routes => src/routes}/api/stacks/+server.ts | 0 .../routes}/api/stacks/[name]/+server.ts | 0 .../api/stacks/[name]/compose/+server.ts | 0 .../routes}/api/stacks/[name]/down/+server.ts | 0 .../routes}/api/stacks/[name]/env/+server.ts | 0 .../api/stacks/[name]/env/validate/+server.ts | 0 .../api/stacks/[name]/restart/+server.ts | 0 .../api/stacks/[name]/start/+server.ts | 0 .../routes}/api/stacks/[name]/stop/+server.ts | 0 .../routes}/api/stacks/sources/+server.ts | 0 {routes => src/routes}/api/system/+server.ts | 0 .../routes}/api/system/disk/+server.ts | 0 {routes => src/routes}/api/users/+server.ts | 0 .../routes}/api/users/[id]/+server.ts | 0 .../routes}/api/users/[id]/mfa/+server.ts | 0 .../routes}/api/users/[id]/roles/+server.ts | 0 {routes => src/routes}/api/volumes/+server.ts | 0 .../routes}/api/volumes/[name]/+server.ts | 0 .../api/volumes/[name]/browse/+server.ts | 0 .../volumes/[name]/browse/content/+server.ts | 0 .../volumes/[name]/browse/release/+server.ts | 0 .../api/volumes/[name]/clone/+server.ts | 0 .../api/volumes/[name]/export/+server.ts | 0 .../api/volumes/[name]/inspect/+server.ts | 0 {routes => src/routes}/audit/+page.svelte | 0 {routes => src/routes}/audit/+server.ts | 0 {routes => src/routes}/audit/users/+server.ts | 0 .../routes}/containers/+page.svelte | 0 .../containers/AutoUpdateSettings.svelte | 0 .../containers/BatchUpdateModal.svelte | 0 .../containers/ContainerInspectModal.svelte | 0 .../containers/ContainerTerminal.svelte | 0 .../routes}/containers/ContainerTile.svelte | 0 .../containers/CreateContainerModal.svelte | 0 .../containers/EditContainerModal.svelte | 0 .../containers/FileBrowserModal.svelte | 0 .../containers/FileBrowserPanel.svelte | 0 .../routes}/dashboard/DraggableGrid.svelte | 0 .../routes}/dashboard/EnvironmentTile.svelte | 0 .../dashboard/EnvironmentTileSkeleton.svelte | 0 .../dashboard-container-stats.svelte | 0 .../dashboard-cpu-memory-bars.svelte | 0 .../dashboard-cpu-memory-charts.svelte | 0 .../dashboard/dashboard-disk-usage.svelte | 0 .../dashboard/dashboard-events-summary.svelte | 0 .../routes}/dashboard/dashboard-header.svelte | 0 .../dashboard/dashboard-health-banner.svelte | 0 .../routes}/dashboard/dashboard-labels.svelte | 0 .../dashboard/dashboard-offline-state.svelte | 0 .../dashboard/dashboard-recent-events.svelte | 0 .../dashboard/dashboard-resource-stats.svelte | 0 .../dashboard/dashboard-status-icons.svelte | 0 .../dashboard/dashboard-top-containers.svelte | 0 {routes => src/routes}/dashboard/index.ts | 0 .../routes}/environments/+page.svelte | 0 {routes => src/routes}/images/+page.server.ts | 0 {routes => src/routes}/images/+page.svelte | 0 .../routes}/images/ImageHistoryModal.svelte | 0 .../routes}/images/ImageLayersView.svelte | 0 .../images/ImagePullProgressPopover.svelte | 0 .../routes}/images/ImageScanModal.svelte | 0 .../routes}/images/PushToRegistryModal.svelte | 0 .../routes}/images/ScanResultsView.svelte | 0 .../images/VulnerabilityScanModal.svelte | 0 {routes => src/routes}/login/+page.svelte | 0 {routes => src/routes}/logs/+page.svelte | 0 {routes => src/routes}/logs/LogViewer.svelte | 0 {routes => src/routes}/logs/LogsPanel.svelte | 0 {routes => src/routes}/networks/+page.svelte | 0 .../networks/ConnectContainerModal.svelte | 0 .../networks/CreateNetworkModal.svelte | 0 .../networks/NetworkInspectModal.svelte | 0 {routes => src/routes}/profile/+page.svelte | 0 .../profile/ChangePasswordModal.svelte | 0 .../routes}/profile/DisableMfaModal.svelte | 0 .../routes}/profile/MfaSetupModal.svelte | 0 {routes => src/routes}/registry/+page.svelte | 0 .../registry/CopyToRegistryModal.svelte | 0 .../routes}/registry/ImagePullModal.svelte | 0 {routes => src/routes}/schedules/+page.svelte | 0 {routes => src/routes}/settings/+page.svelte | 0 .../routes}/settings/about/AboutTab.svelte | 0 .../settings/about/LicenseModal.svelte | 0 .../settings/about/PrivacyModal.svelte | 0 .../routes}/settings/auth/AuthTab.svelte | 0 .../settings/auth/ldap/LdapModal.svelte | 0 .../settings/auth/ldap/LdapSubTab.svelte | 0 .../settings/auth/oidc/OidcModal.svelte | 0 .../settings/auth/oidc/SsoSubTab.svelte | 0 .../settings/auth/roles/RoleModal.svelte | 0 .../settings/auth/roles/RolesSubTab.svelte | 0 .../settings/auth/users/UserModal.svelte | 0 .../settings/auth/users/UsersSubTab.svelte | 0 .../config-sets/ConfigSetModal.svelte | 0 .../settings/config-sets/ConfigSetsTab.svelte | 0 .../environments/EnvironmentModal.svelte | 0 .../environments/EnvironmentsTab.svelte | 0 .../environments/EventTypesEditor.svelte | 0 .../settings/general/GeneralTab.svelte | 0 .../settings/git/GitCredentialModal.svelte | 0 .../settings/git/GitCredentialsTab.svelte | 0 .../settings/git/GitRepositoriesTab.svelte | 0 .../settings/git/GitRepositoryModal.svelte | 0 .../routes}/settings/git/GitTab.svelte | 0 .../settings/license/LicenseTab.svelte | 0 .../notifications/NotificationModal.svelte | 0 .../notifications/NotificationsTab.svelte | 0 .../settings/registries/RegistriesTab.svelte | 0 .../settings/registries/RegistryModal.svelte | 0 {routes => src/routes}/stacks/+page.svelte | 0 .../routes}/stacks/ComposeGraphViewer.svelte | 0 .../stacks/GitDeployProgressPopover.svelte | 0 .../routes}/stacks/GitStackModal.svelte | 0 .../routes}/stacks/StackModal.svelte | 0 {routes => src/routes}/terminal/+page.svelte | 0 .../routes}/terminal/Terminal.svelte | 0 .../routes}/terminal/TerminalEmulator.svelte | 0 .../routes}/terminal/TerminalPanel.svelte | 0 .../routes}/terminal/[id]/+page.svelte | 0 {routes => src/routes}/volumes/+page.svelte | 0 .../routes}/volumes/CloneVolumeModal.svelte | 0 .../routes}/volumes/CreateVolumeModal.svelte | 0 .../routes}/volumes/VolumeBrowserModal.svelte | 0 .../routes}/volumes/VolumeInspectModal.svelte | 0 svelte.config.js | 15 + tsconfig.json | 20 + vite.config.ts | 996 ++++++++++++++++++ 556 files changed, 1390 insertions(+) create mode 100644 Dockerfile create mode 100644 bunfig.toml create mode 100644 components.json create mode 100644 docker-entrypoint.sh create mode 100644 drizzle.config.ts create mode 100644 package.json rename app.css => src/app.css (100%) rename app.d.ts => src/app.d.ts (100%) rename app.html => src/app.html (100%) rename hooks.server.ts => src/hooks.server.ts (100%) rename {images => src/images}/logo.webp (100%) rename {lib => src/lib}/actions/column-resize.ts (100%) rename {lib => src/lib}/assets/favicon.svg (100%) rename {lib => src/lib}/components/AvatarCropper.svelte (100%) rename {lib => src/lib}/components/BatchOperationModal.svelte (100%) rename {lib => src/lib}/components/CodeEditor.svelte (100%) rename {lib => src/lib}/components/ColumnSettingsPopover.svelte (100%) rename {lib => src/lib}/components/CommandPalette.svelte (100%) rename {lib => src/lib}/components/ConfirmPopover.svelte (100%) rename {lib => src/lib}/components/ExecutionLogViewer.svelte (100%) rename {lib => src/lib}/components/MultiSelectFilter.svelte (100%) rename {lib => src/lib}/components/PageHeader.svelte (100%) rename {lib => src/lib}/components/PasswordStrengthIndicator.svelte (100%) rename {lib => src/lib}/components/PullTab.svelte (100%) rename {lib => src/lib}/components/PushTab.svelte (100%) rename {lib => src/lib}/components/ScanTab.svelte (100%) rename {lib => src/lib}/components/ScannerSeverityPills.svelte (100%) rename {lib => src/lib}/components/Sidebar.svelte (100%) rename {lib => src/lib}/components/StackEnvVarsEditor.svelte (100%) rename {lib => src/lib}/components/StackEnvVarsPanel.svelte (100%) rename {lib => src/lib}/components/ThemeSelector.svelte (100%) rename {lib => src/lib}/components/TimezoneSelector.svelte (100%) rename {lib => src/lib}/components/UpdateContainerRow.svelte (100%) rename {lib => src/lib}/components/UpdateStepIndicator.svelte (100%) rename {lib => src/lib}/components/UpdateSummaryStats.svelte (100%) rename {lib => src/lib}/components/VulnerabilityCriteriaBadge.svelte (100%) rename {lib => src/lib}/components/VulnerabilityCriteriaSelector.svelte (100%) rename {lib => src/lib}/components/WhatsNewModal.svelte (100%) rename {lib => src/lib}/components/app-sidebar.svelte (100%) rename {lib => src/lib}/components/cron-editor.svelte (100%) rename {lib => src/lib}/components/data-grid/DataGrid.svelte (100%) rename {lib => src/lib}/components/data-grid/context.ts (100%) rename {lib => src/lib}/components/data-grid/index.ts (100%) rename {lib => src/lib}/components/data-grid/types.ts (100%) rename {lib => src/lib}/components/host-info.svelte (100%) rename {lib => src/lib}/components/icon-picker.svelte (100%) rename {lib => src/lib}/components/main-content.svelte (100%) rename {lib => src/lib}/components/permission-guard.svelte (100%) rename {lib => src/lib}/components/theme-toggle.svelte (100%) rename {lib => src/lib}/components/ui/accordion/accordion-content.svelte (100%) rename {lib => src/lib}/components/ui/accordion/accordion-item.svelte (100%) rename {lib => src/lib}/components/ui/accordion/accordion-trigger.svelte (100%) rename {lib => src/lib}/components/ui/accordion/accordion.svelte (100%) rename {lib => src/lib}/components/ui/accordion/index.ts (100%) rename {lib => src/lib}/components/ui/alert/alert-description.svelte (100%) rename {lib => src/lib}/components/ui/alert/alert-title.svelte (100%) rename {lib => src/lib}/components/ui/alert/alert.svelte (100%) rename {lib => src/lib}/components/ui/alert/index.ts (100%) rename {lib => src/lib}/components/ui/avatar/avatar-fallback.svelte (100%) rename {lib => src/lib}/components/ui/avatar/avatar-image.svelte (100%) rename {lib => src/lib}/components/ui/avatar/avatar.svelte (100%) rename {lib => src/lib}/components/ui/avatar/index.ts (100%) rename {lib => src/lib}/components/ui/badge/badge.svelte (100%) rename {lib => src/lib}/components/ui/badge/index.ts (100%) rename {lib => src/lib}/components/ui/button/button.svelte (100%) rename {lib => src/lib}/components/ui/button/index.ts (100%) rename {lib => src/lib}/components/ui/calendar/calendar-caption.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-cell.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-day.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-grid-body.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-grid-head.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-grid-row.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-grid.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-head-cell.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-header.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-heading.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-month-select.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-month.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-months.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-nav.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-next-button.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-prev-button.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar-year-select.svelte (100%) rename {lib => src/lib}/components/ui/calendar/calendar.svelte (100%) rename {lib => src/lib}/components/ui/calendar/index.ts (100%) rename {lib => src/lib}/components/ui/card/card-action.svelte (100%) rename {lib => src/lib}/components/ui/card/card-content.svelte (100%) rename {lib => src/lib}/components/ui/card/card-description.svelte (100%) rename {lib => src/lib}/components/ui/card/card-footer.svelte (100%) rename {lib => src/lib}/components/ui/card/card-header.svelte (100%) rename {lib => src/lib}/components/ui/card/card-title.svelte (100%) rename {lib => src/lib}/components/ui/card/card.svelte (100%) rename {lib => src/lib}/components/ui/card/index.ts (100%) rename {lib => src/lib}/components/ui/checkbox/checkbox.svelte (100%) rename {lib => src/lib}/components/ui/checkbox/index.ts (100%) rename {lib => src/lib}/components/ui/command/command-dialog.svelte (100%) rename {lib => src/lib}/components/ui/command/command-empty.svelte (100%) rename {lib => src/lib}/components/ui/command/command-group.svelte (100%) rename {lib => src/lib}/components/ui/command/command-input.svelte (100%) rename {lib => src/lib}/components/ui/command/command-item.svelte (100%) rename {lib => src/lib}/components/ui/command/command-link-item.svelte (100%) rename {lib => src/lib}/components/ui/command/command-list.svelte (100%) rename {lib => src/lib}/components/ui/command/command-loading.svelte (100%) rename {lib => src/lib}/components/ui/command/command-separator.svelte (100%) rename {lib => src/lib}/components/ui/command/command-shortcut.svelte (100%) rename {lib => src/lib}/components/ui/command/command.svelte (100%) rename {lib => src/lib}/components/ui/command/index.ts (100%) rename {lib => src/lib}/components/ui/date-picker/date-picker.svelte (100%) rename {lib => src/lib}/components/ui/date-picker/index.ts (100%) rename {lib => src/lib}/components/ui/dialog/dialog-close.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-content.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-description.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-footer.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-header.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-overlay.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-portal.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-title.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog-trigger.svelte (100%) rename {lib => src/lib}/components/ui/dialog/dialog.svelte (100%) rename {lib => src/lib}/components/ui/dialog/index.ts (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-content.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-group.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-item.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-label.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-portal.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-separator.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-sub.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu-trigger.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/dropdown-menu.svelte (100%) rename {lib => src/lib}/components/ui/dropdown-menu/index.ts (100%) rename {lib => src/lib}/components/ui/empty-state/empty-state.svelte (100%) rename {lib => src/lib}/components/ui/empty-state/index.ts (100%) rename {lib => src/lib}/components/ui/empty-state/no-environment.svelte (100%) rename {lib => src/lib}/components/ui/input/index.ts (100%) rename {lib => src/lib}/components/ui/input/input.svelte (100%) rename {lib => src/lib}/components/ui/label/index.ts (100%) rename {lib => src/lib}/components/ui/label/label.svelte (100%) rename {lib => src/lib}/components/ui/popover/index.ts (100%) rename {lib => src/lib}/components/ui/popover/popover-content.svelte (100%) rename {lib => src/lib}/components/ui/popover/popover-trigger.svelte (100%) rename {lib => src/lib}/components/ui/progress/index.ts (100%) rename {lib => src/lib}/components/ui/progress/progress.svelte (100%) rename {lib => src/lib}/components/ui/select/index.ts (100%) rename {lib => src/lib}/components/ui/select/select-content.svelte (100%) rename {lib => src/lib}/components/ui/select/select-group-heading.svelte (100%) rename {lib => src/lib}/components/ui/select/select-group.svelte (100%) rename {lib => src/lib}/components/ui/select/select-item.svelte (100%) rename {lib => src/lib}/components/ui/select/select-label.svelte (100%) rename {lib => src/lib}/components/ui/select/select-scroll-down-button.svelte (100%) rename {lib => src/lib}/components/ui/select/select-scroll-up-button.svelte (100%) rename {lib => src/lib}/components/ui/select/select-separator.svelte (100%) rename {lib => src/lib}/components/ui/select/select-trigger.svelte (100%) rename {lib => src/lib}/components/ui/separator/index.ts (100%) rename {lib => src/lib}/components/ui/separator/separator.svelte (100%) rename {lib => src/lib}/components/ui/sheet/index.ts (100%) rename {lib => src/lib}/components/ui/sheet/sheet-close.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-content.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-description.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-footer.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-header.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-overlay.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-title.svelte (100%) rename {lib => src/lib}/components/ui/sheet/sheet-trigger.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/constants.ts (100%) rename {lib => src/lib}/components/ui/sidebar/context.svelte.ts (100%) rename {lib => src/lib}/components/ui/sidebar/index.ts (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-content.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-footer.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-group-action.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-group-content.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-group-label.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-group.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-header.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-input.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-inset.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-action.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-badge.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-button.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-item.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-skeleton.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-sub-button.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-sub-item.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu-sub.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-menu.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-provider.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-rail.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-separator.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar-trigger.svelte (100%) rename {lib => src/lib}/components/ui/sidebar/sidebar.svelte (100%) rename {lib => src/lib}/components/ui/skeleton/index.ts (100%) rename {lib => src/lib}/components/ui/skeleton/skeleton.svelte (100%) rename {lib => src/lib}/components/ui/sonner/index.ts (100%) rename {lib => src/lib}/components/ui/sonner/sonner.svelte (100%) rename {lib => src/lib}/components/ui/switch/index.ts (100%) rename {lib => src/lib}/components/ui/switch/switch.svelte (100%) rename {lib => src/lib}/components/ui/table/index.ts (100%) rename {lib => src/lib}/components/ui/table/table-body.svelte (100%) rename {lib => src/lib}/components/ui/table/table-caption.svelte (100%) rename {lib => src/lib}/components/ui/table/table-cell.svelte (100%) rename {lib => src/lib}/components/ui/table/table-footer.svelte (100%) rename {lib => src/lib}/components/ui/table/table-head.svelte (100%) rename {lib => src/lib}/components/ui/table/table-header.svelte (100%) rename {lib => src/lib}/components/ui/table/table-row.svelte (100%) rename {lib => src/lib}/components/ui/table/table.svelte (100%) rename {lib => src/lib}/components/ui/tabs/index.ts (100%) rename {lib => src/lib}/components/ui/tabs/tabs-content.svelte (100%) rename {lib => src/lib}/components/ui/tabs/tabs-list.svelte (100%) rename {lib => src/lib}/components/ui/tabs/tabs-trigger.svelte (100%) rename {lib => src/lib}/components/ui/tabs/tabs.svelte (100%) rename {lib => src/lib}/components/ui/textarea/index.ts (100%) rename {lib => src/lib}/components/ui/textarea/textarea.svelte (100%) rename {lib => src/lib}/components/ui/toggle-pill/index.ts (100%) rename {lib => src/lib}/components/ui/toggle-pill/toggle-group.svelte (100%) rename {lib => src/lib}/components/ui/toggle-pill/toggle-pill.svelte (100%) rename {lib => src/lib}/components/ui/toggle-pill/toggle-switch.svelte (100%) rename {lib => src/lib}/components/ui/tooltip/index.ts (100%) rename {lib => src/lib}/components/ui/tooltip/tooltip-content.svelte (100%) rename {lib => src/lib}/components/ui/tooltip/tooltip-trigger.svelte (100%) rename {lib => src/lib}/config/grid-columns.ts (100%) rename {lib => src/lib}/data/changelog.json (100%) rename {lib => src/lib}/data/dependencies.json (100%) rename {lib => src/lib}/hooks/is-mobile.svelte.ts (100%) rename {lib => src/lib}/index.ts (100%) rename {lib => src/lib}/server/audit-events.ts (100%) rename {lib => src/lib}/server/audit.ts (100%) rename {lib => src/lib}/server/auth.ts (100%) rename {lib => src/lib}/server/authorize.ts (100%) rename {lib => src/lib}/server/db.ts (100%) rename {lib => src/lib}/server/db/connection.ts (100%) rename {lib => src/lib}/server/db/drizzle.ts (100%) rename {lib => src/lib}/server/db/schema/index.ts (100%) rename {lib => src/lib}/server/db/schema/pg-schema.ts (100%) rename {lib => src/lib}/server/docker.ts (100%) rename {lib => src/lib}/server/event-collector.ts (100%) rename {lib => src/lib}/server/git.ts (100%) rename {lib => src/lib}/server/hawser.ts (100%) rename {lib => src/lib}/server/license.ts (100%) rename {lib => src/lib}/server/metrics-collector.ts (100%) rename {lib => src/lib}/server/notifications.ts (100%) rename {lib => src/lib}/server/scanner.ts (100%) rename {lib => src/lib}/server/scheduler/index.ts (100%) rename {lib => src/lib}/server/scheduler/tasks/container-update.ts (100%) rename {lib => src/lib}/server/scheduler/tasks/env-update-check.ts (100%) rename {lib => src/lib}/server/scheduler/tasks/git-stack-sync.ts (100%) rename {lib => src/lib}/server/scheduler/tasks/system-cleanup.ts (100%) rename {lib => src/lib}/server/scheduler/tasks/update-utils.ts (100%) rename {lib => src/lib}/server/stacks.ts (100%) rename {lib => src/lib}/server/subprocess-manager.ts (100%) rename {lib => src/lib}/server/subprocesses/event-subprocess.ts (100%) rename {lib => src/lib}/server/subprocesses/metrics-subprocess.ts (100%) rename {lib => src/lib}/server/uptime.ts (100%) rename {lib => src/lib}/stores/audit-events.ts (100%) rename {lib => src/lib}/stores/auth.ts (100%) rename {lib => src/lib}/stores/dashboard.ts (100%) rename {lib => src/lib}/stores/environment.ts (100%) rename {lib => src/lib}/stores/events.ts (100%) rename {lib => src/lib}/stores/grid-preferences.ts (100%) rename {lib => src/lib}/stores/license.ts (100%) rename {lib => src/lib}/stores/settings.ts (100%) rename {lib => src/lib}/stores/stats.ts (100%) rename {lib => src/lib}/stores/theme.ts (100%) rename {lib => src/lib}/themes.ts (100%) rename {lib => src/lib}/types.ts (100%) rename {lib => src/lib}/utils.ts (100%) rename {lib => src/lib}/utils/icons.ts (100%) rename {lib => src/lib}/utils/ip.ts (100%) rename {lib => src/lib}/utils/label-colors.ts (100%) rename {lib => src/lib}/utils/update-steps.ts (100%) rename {lib => src/lib}/utils/version.ts (100%) rename {routes => src/routes}/+layout.server.ts (100%) rename {routes => src/routes}/+layout.svelte (100%) rename {routes => src/routes}/+layout.ts (100%) rename {routes => src/routes}/+page.svelte (100%) rename {routes => src/routes}/activity/+page.svelte (100%) rename {routes => src/routes}/alerts/+page.svelte (100%) rename {routes => src/routes}/api/activity/+server.ts (100%) rename {routes => src/routes}/api/activity/containers/+server.ts (100%) rename {routes => src/routes}/api/activity/events/+server.ts (100%) rename {routes => src/routes}/api/activity/stats/+server.ts (100%) rename {routes => src/routes}/api/audit/+server.ts (100%) rename {routes => src/routes}/api/audit/events/+server.ts (100%) rename {routes => src/routes}/api/audit/export/+server.ts (100%) rename {routes => src/routes}/api/audit/users/+server.ts (100%) rename {routes => src/routes}/api/auth/ldap/+server.ts (100%) rename {routes => src/routes}/api/auth/ldap/[id]/+server.ts (100%) rename {routes => src/routes}/api/auth/ldap/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/auth/login/+server.ts (100%) rename {routes => src/routes}/api/auth/logout/+server.ts (100%) rename {routes => src/routes}/api/auth/oidc/+server.ts (100%) rename {routes => src/routes}/api/auth/oidc/[id]/+server.ts (100%) rename {routes => src/routes}/api/auth/oidc/[id]/initiate/+server.ts (100%) rename {routes => src/routes}/api/auth/oidc/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/auth/oidc/callback/+server.ts (100%) rename {routes => src/routes}/api/auth/providers/+server.ts (100%) rename {routes => src/routes}/api/auth/session/+server.ts (100%) rename {routes => src/routes}/api/auth/settings/+server.ts (100%) rename {routes => src/routes}/api/auto-update/+server.ts (100%) rename {routes => src/routes}/api/auto-update/[containerName]/+server.ts (100%) rename {routes => src/routes}/api/batch/+server.ts (100%) rename {routes => src/routes}/api/changelog/+server.ts (100%) rename {routes => src/routes}/api/config-sets/+server.ts (100%) rename {routes => src/routes}/api/config-sets/[id]/+server.ts (100%) rename {routes => src/routes}/api/containers/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/exec/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/chmod/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/content/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/create/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/delete/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/download/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/rename/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/files/upload/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/inspect/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/logs/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/logs/stream/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/pause/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/rename/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/restart/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/start/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/stats/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/stop/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/top/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/unpause/+server.ts (100%) rename {routes => src/routes}/api/containers/[id]/update/+server.ts (100%) rename {routes => src/routes}/api/containers/batch-update-stream/+server.ts (100%) rename {routes => src/routes}/api/containers/batch-update/+server.ts (100%) rename {routes => src/routes}/api/containers/check-updates/+server.ts (100%) rename {routes => src/routes}/api/containers/pending-updates/+server.ts (100%) rename {routes => src/routes}/api/containers/sizes/+server.ts (100%) rename {routes => src/routes}/api/containers/stats/+server.ts (100%) rename {routes => src/routes}/api/dashboard/preferences/+server.ts (100%) rename {routes => src/routes}/api/dashboard/stats/+server.ts (100%) rename {routes => src/routes}/api/dashboard/stats/stream/+server.ts (100%) rename {routes => src/routes}/api/dependencies/+server.ts (100%) rename {routes => src/routes}/api/environments/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/notifications/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/notifications/[notificationId]/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/timezone/+server.ts (100%) rename {routes => src/routes}/api/environments/[id]/update-check/+server.ts (100%) rename {routes => src/routes}/api/environments/detect-socket/+server.ts (100%) rename {routes => src/routes}/api/environments/test/+server.ts (100%) rename {routes => src/routes}/api/events/+server.ts (100%) rename {routes => src/routes}/api/git/credentials/+server.ts (100%) rename {routes => src/routes}/api/git/credentials/[id]/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/[id]/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/[id]/deploy/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/[id]/sync/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/git/repositories/test/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/deploy-stream/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/deploy/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/env-files/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/sync/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/git/stacks/[id]/webhook/+server.ts (100%) rename {routes => src/routes}/api/git/webhook/[id]/+server.ts (100%) rename {routes => src/routes}/api/hawser/connect/+server.ts (100%) rename {routes => src/routes}/api/hawser/tokens/+server.ts (100%) rename {routes => src/routes}/api/health/+server.ts (100%) rename {routes => src/routes}/api/health/database/+server.ts (100%) rename {routes => src/routes}/api/host/+server.ts (100%) rename {routes => src/routes}/api/images/+server.ts (100%) rename {routes => src/routes}/api/images/[id]/+server.ts (100%) rename {routes => src/routes}/api/images/[id]/export/+server.ts (100%) rename {routes => src/routes}/api/images/[id]/history/+server.ts (100%) rename {routes => src/routes}/api/images/[id]/tag/+server.ts (100%) rename {routes => src/routes}/api/images/pull/+server.ts (100%) rename {routes => src/routes}/api/images/push/+server.ts (100%) rename {routes => src/routes}/api/images/scan/+server.ts (100%) rename {routes => src/routes}/api/legal/license/+server.ts (100%) rename {routes => src/routes}/api/legal/privacy/+server.ts (100%) rename {routes => src/routes}/api/license/+server.ts (100%) rename {routes => src/routes}/api/logs/merged/+server.ts (100%) rename {routes => src/routes}/api/metrics/+server.ts (100%) rename {routes => src/routes}/api/networks/+server.ts (100%) rename {routes => src/routes}/api/networks/[id]/+server.ts (100%) rename {routes => src/routes}/api/networks/[id]/connect/+server.ts (100%) rename {routes => src/routes}/api/networks/[id]/disconnect/+server.ts (100%) rename {routes => src/routes}/api/networks/[id]/inspect/+server.ts (100%) rename {routes => src/routes}/api/notifications/+server.ts (100%) rename {routes => src/routes}/api/notifications/[id]/+server.ts (100%) rename {routes => src/routes}/api/notifications/[id]/test/+server.ts (100%) rename {routes => src/routes}/api/notifications/test/+server.ts (100%) rename {routes => src/routes}/api/notifications/trigger-test/+server.ts (100%) rename {routes => src/routes}/api/preferences/favorite-groups/+server.ts (100%) rename {routes => src/routes}/api/preferences/favorites/+server.ts (100%) rename {routes => src/routes}/api/preferences/grid/+server.ts (100%) rename {routes => src/routes}/api/profile/+server.ts (100%) rename {routes => src/routes}/api/profile/avatar/+server.ts (100%) rename {routes => src/routes}/api/profile/preferences/+server.ts (100%) rename {routes => src/routes}/api/prune/all/+server.ts (100%) rename {routes => src/routes}/api/prune/containers/+server.ts (100%) rename {routes => src/routes}/api/prune/images/+server.ts (100%) rename {routes => src/routes}/api/prune/networks/+server.ts (100%) rename {routes => src/routes}/api/prune/volumes/+server.ts (100%) rename {routes => src/routes}/api/registries/+server.ts (100%) rename {routes => src/routes}/api/registries/[id]/+server.ts (100%) rename {routes => src/routes}/api/registries/[id]/default/+server.ts (100%) rename {routes => src/routes}/api/registry/catalog/+server.ts (100%) rename {routes => src/routes}/api/registry/image/+server.ts (100%) rename {routes => src/routes}/api/registry/search/+server.ts (100%) rename {routes => src/routes}/api/registry/tags/+server.ts (100%) rename {routes => src/routes}/api/roles/+server.ts (100%) rename {routes => src/routes}/api/roles/[id]/+server.ts (100%) rename {routes => src/routes}/api/schedules/+server.ts (100%) rename {routes => src/routes}/api/schedules/[type]/[id]/+server.ts (100%) rename {routes => src/routes}/api/schedules/[type]/[id]/run/+server.ts (100%) rename {routes => src/routes}/api/schedules/[type]/[id]/toggle/+server.ts (100%) rename {routes => src/routes}/api/schedules/executions/+server.ts (100%) rename {routes => src/routes}/api/schedules/executions/[id]/+server.ts (100%) rename {routes => src/routes}/api/schedules/settings/+server.ts (100%) rename {routes => src/routes}/api/schedules/stream/+server.ts (100%) rename {routes => src/routes}/api/schedules/system/[id]/toggle/+server.ts (100%) rename {routes => src/routes}/api/settings/general/+server.ts (100%) rename {routes => src/routes}/api/settings/scanner/+server.ts (100%) rename {routes => src/routes}/api/stacks/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/compose/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/down/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/env/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/env/validate/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/restart/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/start/+server.ts (100%) rename {routes => src/routes}/api/stacks/[name]/stop/+server.ts (100%) rename {routes => src/routes}/api/stacks/sources/+server.ts (100%) rename {routes => src/routes}/api/system/+server.ts (100%) rename {routes => src/routes}/api/system/disk/+server.ts (100%) rename {routes => src/routes}/api/users/+server.ts (100%) rename {routes => src/routes}/api/users/[id]/+server.ts (100%) rename {routes => src/routes}/api/users/[id]/mfa/+server.ts (100%) rename {routes => src/routes}/api/users/[id]/roles/+server.ts (100%) rename {routes => src/routes}/api/volumes/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/browse/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/browse/content/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/browse/release/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/clone/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/export/+server.ts (100%) rename {routes => src/routes}/api/volumes/[name]/inspect/+server.ts (100%) rename {routes => src/routes}/audit/+page.svelte (100%) rename {routes => src/routes}/audit/+server.ts (100%) rename {routes => src/routes}/audit/users/+server.ts (100%) rename {routes => src/routes}/containers/+page.svelte (100%) rename {routes => src/routes}/containers/AutoUpdateSettings.svelte (100%) rename {routes => src/routes}/containers/BatchUpdateModal.svelte (100%) rename {routes => src/routes}/containers/ContainerInspectModal.svelte (100%) rename {routes => src/routes}/containers/ContainerTerminal.svelte (100%) rename {routes => src/routes}/containers/ContainerTile.svelte (100%) rename {routes => src/routes}/containers/CreateContainerModal.svelte (100%) rename {routes => src/routes}/containers/EditContainerModal.svelte (100%) rename {routes => src/routes}/containers/FileBrowserModal.svelte (100%) rename {routes => src/routes}/containers/FileBrowserPanel.svelte (100%) rename {routes => src/routes}/dashboard/DraggableGrid.svelte (100%) rename {routes => src/routes}/dashboard/EnvironmentTile.svelte (100%) rename {routes => src/routes}/dashboard/EnvironmentTileSkeleton.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-container-stats.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-cpu-memory-bars.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-cpu-memory-charts.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-disk-usage.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-events-summary.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-header.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-health-banner.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-labels.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-offline-state.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-recent-events.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-resource-stats.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-status-icons.svelte (100%) rename {routes => src/routes}/dashboard/dashboard-top-containers.svelte (100%) rename {routes => src/routes}/dashboard/index.ts (100%) rename {routes => src/routes}/environments/+page.svelte (100%) rename {routes => src/routes}/images/+page.server.ts (100%) rename {routes => src/routes}/images/+page.svelte (100%) rename {routes => src/routes}/images/ImageHistoryModal.svelte (100%) rename {routes => src/routes}/images/ImageLayersView.svelte (100%) rename {routes => src/routes}/images/ImagePullProgressPopover.svelte (100%) rename {routes => src/routes}/images/ImageScanModal.svelte (100%) rename {routes => src/routes}/images/PushToRegistryModal.svelte (100%) rename {routes => src/routes}/images/ScanResultsView.svelte (100%) rename {routes => src/routes}/images/VulnerabilityScanModal.svelte (100%) rename {routes => src/routes}/login/+page.svelte (100%) rename {routes => src/routes}/logs/+page.svelte (100%) rename {routes => src/routes}/logs/LogViewer.svelte (100%) rename {routes => src/routes}/logs/LogsPanel.svelte (100%) rename {routes => src/routes}/networks/+page.svelte (100%) rename {routes => src/routes}/networks/ConnectContainerModal.svelte (100%) rename {routes => src/routes}/networks/CreateNetworkModal.svelte (100%) rename {routes => src/routes}/networks/NetworkInspectModal.svelte (100%) rename {routes => src/routes}/profile/+page.svelte (100%) rename {routes => src/routes}/profile/ChangePasswordModal.svelte (100%) rename {routes => src/routes}/profile/DisableMfaModal.svelte (100%) rename {routes => src/routes}/profile/MfaSetupModal.svelte (100%) rename {routes => src/routes}/registry/+page.svelte (100%) rename {routes => src/routes}/registry/CopyToRegistryModal.svelte (100%) rename {routes => src/routes}/registry/ImagePullModal.svelte (100%) rename {routes => src/routes}/schedules/+page.svelte (100%) rename {routes => src/routes}/settings/+page.svelte (100%) rename {routes => src/routes}/settings/about/AboutTab.svelte (100%) rename {routes => src/routes}/settings/about/LicenseModal.svelte (100%) rename {routes => src/routes}/settings/about/PrivacyModal.svelte (100%) rename {routes => src/routes}/settings/auth/AuthTab.svelte (100%) rename {routes => src/routes}/settings/auth/ldap/LdapModal.svelte (100%) rename {routes => src/routes}/settings/auth/ldap/LdapSubTab.svelte (100%) rename {routes => src/routes}/settings/auth/oidc/OidcModal.svelte (100%) rename {routes => src/routes}/settings/auth/oidc/SsoSubTab.svelte (100%) rename {routes => src/routes}/settings/auth/roles/RoleModal.svelte (100%) rename {routes => src/routes}/settings/auth/roles/RolesSubTab.svelte (100%) rename {routes => src/routes}/settings/auth/users/UserModal.svelte (100%) rename {routes => src/routes}/settings/auth/users/UsersSubTab.svelte (100%) rename {routes => src/routes}/settings/config-sets/ConfigSetModal.svelte (100%) rename {routes => src/routes}/settings/config-sets/ConfigSetsTab.svelte (100%) rename {routes => src/routes}/settings/environments/EnvironmentModal.svelte (100%) rename {routes => src/routes}/settings/environments/EnvironmentsTab.svelte (100%) rename {routes => src/routes}/settings/environments/EventTypesEditor.svelte (100%) rename {routes => src/routes}/settings/general/GeneralTab.svelte (100%) rename {routes => src/routes}/settings/git/GitCredentialModal.svelte (100%) rename {routes => src/routes}/settings/git/GitCredentialsTab.svelte (100%) rename {routes => src/routes}/settings/git/GitRepositoriesTab.svelte (100%) rename {routes => src/routes}/settings/git/GitRepositoryModal.svelte (100%) rename {routes => src/routes}/settings/git/GitTab.svelte (100%) rename {routes => src/routes}/settings/license/LicenseTab.svelte (100%) rename {routes => src/routes}/settings/notifications/NotificationModal.svelte (100%) rename {routes => src/routes}/settings/notifications/NotificationsTab.svelte (100%) rename {routes => src/routes}/settings/registries/RegistriesTab.svelte (100%) rename {routes => src/routes}/settings/registries/RegistryModal.svelte (100%) rename {routes => src/routes}/stacks/+page.svelte (100%) rename {routes => src/routes}/stacks/ComposeGraphViewer.svelte (100%) rename {routes => src/routes}/stacks/GitDeployProgressPopover.svelte (100%) rename {routes => src/routes}/stacks/GitStackModal.svelte (100%) rename {routes => src/routes}/stacks/StackModal.svelte (100%) rename {routes => src/routes}/terminal/+page.svelte (100%) rename {routes => src/routes}/terminal/Terminal.svelte (100%) rename {routes => src/routes}/terminal/TerminalEmulator.svelte (100%) rename {routes => src/routes}/terminal/TerminalPanel.svelte (100%) rename {routes => src/routes}/terminal/[id]/+page.svelte (100%) rename {routes => src/routes}/volumes/+page.svelte (100%) rename {routes => src/routes}/volumes/CloneVolumeModal.svelte (100%) rename {routes => src/routes}/volumes/CreateVolumeModal.svelte (100%) rename {routes => src/routes}/volumes/VolumeBrowserModal.svelte (100%) rename {routes => src/routes}/volumes/VolumeInspectModal.svelte (100%) create mode 100644 svelte.config.js create mode 100644 tsconfig.json create mode 100644 vite.config.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6f8aa0d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,86 @@ +# Build stage - using Debian to avoid Alpine musl thread creation issues +# Alpine's musl libc causes rayon/tokio thread pool panics during svelte-adapter-bun build +FROM oven/bun:1.3.5-debian AS builder + +WORKDIR /app + +# Install build dependencies +RUN apt-get update && apt-get install -y --no-install-recommends jq git && rm -rf /var/lib/apt/lists/* + +# Copy package files and install ALL dependencies (needed for build) +COPY package.json bun.lock* bunfig.toml ./ +RUN bun install --frozen-lockfile + +# Copy source code and build +COPY . . + +# Build with parallelism - dedicated build VM has 16 CPUs and 32GB RAM +# Increased memory limits for parallel compilation with larger semi-space for GC +RUN NODE_OPTIONS="--max-old-space-size=8192 --max-semi-space-size=128" bun run build + +# Production stage - minimal Alpine with Bun runtime +FROM oven/bun:1.3.5-alpine + +WORKDIR /app + +# Install runtime dependencies, create user +# Add sqlite for emergency scripts, git for stack git operations, curl for healthchecks +# Add docker-cli and docker-cli-compose for stack management (uses host's docker socket) +# Add openssh-client for SSH key authentication with git repositories +# Upgrade all packages to latest versions for security patches +RUN apk upgrade --no-cache \ + && apk add --no-cache curl git tini su-exec sqlite docker-cli docker-cli-compose openssh-client iproute2 \ + && addgroup -g 1001 dockhand \ + && adduser -u 1001 -G dockhand -h /home/dockhand -D dockhand + +# Copy package files and install production dependencies +# This is needed because svelte-adapter-bun externalizes some packages (croner, etc.) +# that need to be available at runtime. Installing at build time is more reliable +# than Bun's auto-install which requires network access and writable cache. +COPY package.json bun.lock* ./ +RUN bun install --production --frozen-lockfile + +# Copy built application (Bun adapter output) +COPY --from=builder /app/build ./build + +# Copy bundled subprocess scripts (built by scripts/build-subprocesses.ts) +COPY --from=builder /app/build/subprocesses/ ./subprocesses/ + +# Copy database migrations +COPY drizzle/ ./drizzle/ +COPY drizzle-pg/ ./drizzle-pg/ + +# Copy legal documents +COPY LICENSE.txt PRIVACY.txt ./ + +# Copy entrypoint script +COPY docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +# Copy emergency scripts (only the emergency subfolder, not license generation scripts) +COPY scripts/emergency/ ./scripts/ +RUN chmod +x ./scripts/*.sh 2>/dev/null || true + +# Create directories with proper ownership +RUN mkdir -p /home/dockhand/.dockhand/stacks /app/data \ + && chown -R dockhand:dockhand /app /home/dockhand + +EXPOSE 3000 + +# Runtime configuration +ENV NODE_ENV=production +ENV PORT=3000 +ENV HOST=0.0.0.0 +ENV DATA_DIR=/app/data +ENV HOME=/home/dockhand + +# User/group IDs - customize with -e PUID=1000 -e PGID=1000 +# The entrypoint will recreate the dockhand user with these IDs +ENV PUID=1001 +ENV PGID=1001 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:3000/ || exit 1 + +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"] +CMD ["bun", "run", "./build/index.js"] diff --git a/bunfig.toml b/bunfig.toml new file mode 100644 index 0000000..51bc0ff --- /dev/null +++ b/bunfig.toml @@ -0,0 +1,9 @@ +# Bun configuration for Dockhand + +[install] +# Use exact versions for reproducible builds +exact = true + +[run] +# Enable source maps for better error messages +sourcemap = "external" diff --git a/components.json b/components.json new file mode 100644 index 0000000..c5d91b4 --- /dev/null +++ b/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://shadcn-svelte.com/schema.json", + "tailwind": { + "css": "src/app.css", + "baseColor": "slate" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "hooks": "$lib/hooks", + "lib": "$lib" + }, + "typescript": true, + "registry": "https://shadcn-svelte.com/registry" +} diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..ecbc9b2 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,122 @@ +#!/bin/sh +set -e + +# Dockhand Docker Entrypoint +# === Configuration === +PUID=${PUID:-1001} +PGID=${PGID:-1001} + +# === Detect if running as root === +RUNNING_AS_ROOT=false +if [ "$(id -u)" = "0" ]; then + RUNNING_AS_ROOT=true +fi + +# === User Setup === +# Root mode: PUID=0 requested OR already running as root with default PUID/PGID +if [ "$PUID" = "0" ]; then + echo "Running as root user (PUID=0)" + RUN_USER="root" +elif [ "$RUNNING_AS_ROOT" = "true" ] && [ "$PUID" = "1001" ] && [ "$PGID" = "1001" ]; then + echo "Running as root user" + RUN_USER="root" +else + RUN_USER="dockhand" + # Only modify if PUID/PGID differ from image defaults (1001:1001) + if [ "$PUID" != "1001" ] || [ "$PGID" != "1001" ]; then + echo "Configuring user with PUID=$PUID PGID=$PGID" + + # Remove existing dockhand user/group (only dockhand, not others) + deluser dockhand 2>/dev/null || true + delgroup dockhand 2>/dev/null || true + + # Check for UID conflicts - warn but don't delete other users + if getent passwd "$PUID" >/dev/null 2>&1; then + EXISTING=$(getent passwd "$PUID" | cut -d: -f1) + echo "WARNING: UID $PUID already in use by '$EXISTING'. Using default UID 1001." + PUID=1001 + fi + + # Handle GID - reuse existing group or create new + if getent group "$PGID" >/dev/null 2>&1; then + TARGET_GROUP=$(getent group "$PGID" | cut -d: -f1) + else + addgroup -g "$PGID" dockhand + TARGET_GROUP="dockhand" + fi + + adduser -u "$PUID" -G "$TARGET_GROUP" -h /home/dockhand -D dockhand + fi + + # === Directory Ownership === + chown -R dockhand:dockhand /app/data /home/dockhand 2>/dev/null || true + + if [ -n "$DATA_DIR" ] && [ "$DATA_DIR" != "/app/data" ] && [ "$DATA_DIR" != "./data" ]; then + mkdir -p "$DATA_DIR" + chown -R dockhand:dockhand "$DATA_DIR" 2>/dev/null || true + fi +fi + +# === Docker Socket Access (Optional) === +# Check if Docker socket is mounted and accessible +# Socket path can be configured via environment-specific settings in the app +SOCKET_PATH="/var/run/docker.sock" + +if [ -S "$SOCKET_PATH" ]; then + # Socket exists - check if readable + if [ "$RUN_USER" != "root" ]; then + if ! su-exec "$RUN_USER" test -r "$SOCKET_PATH" 2>/dev/null; then + SOCKET_GID=$(stat -c '%g' "$SOCKET_PATH" 2>/dev/null || echo "unknown") + echo "WARNING: Docker socket at $SOCKET_PATH is not readable by dockhand user" + echo "" + echo "To use local Docker, fix with one of these options:" + echo "" + echo " 1. Add container to docker group (GID: $SOCKET_GID):" + echo " docker run --group-add $SOCKET_GID ..." + echo "" + echo " 2. Use a socket proxy:" + echo " Configure a 'direct' environment pointing to tcp://socket-proxy:2375" + echo "" + echo " 3. Make socket world-readable (less secure):" + echo " chmod 666 /var/run/docker.sock" + echo "" + echo "Continuing startup - configure environments via the web UI..." + else + echo "Docker socket accessible at $SOCKET_PATH" + fi + else + echo "Docker socket accessible at $SOCKET_PATH" + fi + + # === Detect Docker Host Hostname (for license validation) === + # Query Docker API to get the real host hostname (not container ID) + if [ -z "$DOCKHAND_HOSTNAME" ]; then + DETECTED_HOSTNAME=$(curl -s --unix-socket "$SOCKET_PATH" http://localhost/info 2>/dev/null | sed -n 's/.*"Name":"\([^"]*\)".*/\1/p') + if [ -n "$DETECTED_HOSTNAME" ]; then + export DOCKHAND_HOSTNAME="$DETECTED_HOSTNAME" + echo "Detected Docker host hostname: $DOCKHAND_HOSTNAME" + fi + else + echo "Using configured hostname: $DOCKHAND_HOSTNAME" + fi +else + echo "No Docker socket found at $SOCKET_PATH" + echo "Configure Docker environments via the web UI (Settings > Environments)" +fi + +# === Run Application === +if [ "$RUN_USER" = "root" ]; then + # Running as root - execute directly + if [ "$1" = "" ]; then + exec bun run ./build/index.js + else + exec "$@" + fi +else + # Running as dockhand user + if [ "$1" = "" ]; then + exec su-exec dockhand bun run ./build/index.js + else + exec su-exec dockhand "$@" + fi +fi diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..44f2d39 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,16 @@ +import { defineConfig } from 'drizzle-kit'; + +const databaseUrl = process.env.DATABASE_URL; +const isPostgres = databaseUrl && (databaseUrl.startsWith('postgres://') || databaseUrl.startsWith('postgresql://')); + +export default defineConfig({ + // Use different schema files for SQLite vs PostgreSQL + schema: isPostgres + ? './src/lib/server/db/schema/pg-schema.ts' + : './src/lib/server/db/schema/index.ts', + out: isPostgres ? './drizzle-pg' : './drizzle', + dialect: isPostgres ? 'postgresql' : 'sqlite', + dbCredentials: isPostgres + ? { url: databaseUrl! } + : { url: `file:${process.env.DATA_DIR || './data'}/dockhand.db` } +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..24cc896 --- /dev/null +++ b/package.json @@ -0,0 +1,110 @@ +{ + "name": "dockhand", + "private": true, + "version": "1.0.4", + "type": "module", + "scripts": { + "dev": "bunx --bun vite dev", + "prebuild": "bunx license-checker --json --production | jq 'to_entries | map({name: (.key | split(\"@\")[0:-1] | join(\"@\")), version: (.key | split(\"@\")[-1]), license: .value.licenses, repository: .value.repository}) | sort_by(.name)' > src/lib/data/dependencies.json.tmp && mv src/lib/data/dependencies.json.tmp src/lib/data/dependencies.json || true", + "build": "bunx --bun vite build && bun scripts/patch-build.ts && bun scripts/build-subprocesses.ts", + "start": "bun ./build/index.js", + "preview": "bun ./build/index.js", + "prepare": "bunx --bun svelte-kit sync || echo ''", + "check": "bunx --bun svelte-kit sync && bunx --bun svelte-check --tsconfig ./tsconfig.json", + "check:watch": "bunx --bun svelte-kit sync && bunx --bun svelte-check --tsconfig ./tsconfig.json --watch", + "test": "bun test", + "test:smoke": "bun test tests/api-smoke.test.ts", + "test:containers": "bun test tests/container-lifecycle.test.ts", + "test:notifications": "bun test tests/notifications.test.ts", + "test:hawser": "bun test tests/hawser-connection.test.ts", + "test:build": "SKIP_BUILD_TEST=1 bun test tests/build.test.ts", + "test:postgres": "bun test tests/database-postgres.test.ts", + "test:crud": "bun test tests/crud-operations.test.ts", + "test:scheduling": "bun test tests/scheduling.test.ts", + "test:images": "bun test tests/images.test.ts", + "test:volumes": "bun test tests/volumes-networks.test.ts", + "test:stacks": "bun test tests/stacks.test.ts", + "test:stacks:matrix": "bun test tests/stack-matrix.test.ts", + "test:stacks:git": "bun test tests/stack-git-flow.test.ts", + "test:stacks:env": "bun test tests/stack-env-vars.test.ts", + "test:stacks:all": "bun test tests/stack-*.test.ts tests/stacks.test.ts", + "test:files": "bun test tests/container-files.test.ts", + "test:license": "bun test tests/license.test.ts", + "test:activity": "bun test tests/activity-dashboard.test.ts", + "test:all": "bun test tests/", + "test:quick": "bun test tests/api-smoke.test.ts tests/notifications.test.ts", + "test:integration": "bun test tests/api-smoke.test.ts tests/crud-operations.test.ts tests/scheduling.test.ts tests/hawser-connection.test.ts", + "test:e2e": "bunx playwright test tests/e2e/", + "generate:legal": "bun scripts/generate-legal-pages.ts" + }, + "dependencies": { + "@codemirror/autocomplete": "6.20.0", + "@codemirror/commands": "6.10.0", + "@codemirror/lang-css": "6.3.1", + "@codemirror/lang-html": "6.4.11", + "@codemirror/lang-javascript": "6.2.4", + "@codemirror/lang-json": "6.0.2", + "@codemirror/lang-markdown": "6.5.0", + "@codemirror/lang-python": "6.2.1", + "@codemirror/lang-sql": "6.10.0", + "@codemirror/lang-xml": "6.1.0", + "@codemirror/language": "6.11.3", + "@codemirror/search": "6.5.11", + "@lezer/highlight": "1.2.3", + "@lucide/lab": "^0.1.2", + "croner": "9.1.0", + "cronstrue": "3.9.0", + "drizzle-orm": "0.45.0", + "js-yaml": "^4.1.1", + "ldapts": "^8.0.9", + "nodemailer": "^7.0.11", + "otpauth": "^9.4.1", + "postgres": "3.4.7", + "qrcode": "^1.5.4", + "svelte-dnd-action": "0.9.68", + "svelte-sonner": "1.0.7" + }, + "devDependencies": { + "@codemirror/lang-yaml": "^6.1.2", + "@codemirror/state": "^6.5.2", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "^6.38.8", + "@internationalized/date": "^3.10.0", + "@layerstack/tailwind": "^1.0.1", + "@lucide/svelte": "^0.544.0", + "@playwright/test": "1.57.0", + "@sveltejs/kit": "^2.48.5", + "@sveltejs/vite-plugin-svelte": "^6.2.1", + "@tailwindcss/vite": "^4.1.17", + "@types/bun": "^1.2.5", + "@types/js-yaml": "^4.0.9", + "@types/nodemailer": "^7.0.4", + "@types/qrcode": "^1.5.6", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/xterm": "^5.5.0", + "autoprefixer": "^10.4.22", + "bits-ui": "^2.14.4", + "clsx": "^2.1.1", + "codemirror": "^6.0.2", + "cytoscape": "^3.33.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.2.0", + "drizzle-kit": "0.31.8", + "layerchart": "^1.0.12", + "lucide-svelte": "^0.555.0", + "mode-watcher": "^1.1.0", + "postcss": "^8.5.6", + "svelte": "^5.43.8", + "svelte-adapter-bun": "1.0.1", + "svelte-check": "^4.3.4", + "svelte-easy-crop": "^5.0.0", + "svelte-virtual-scroll-list": "^1.3.0", + "tailwind-merge": "^3.4.0", + "tailwind-variants": "^3.2.2", + "tailwindcss": "^4.1.17", + "tw-animate-css": "^1.4.0", + "typescript": "^5.9.3", + "vite": "^7.2.2" + } +} diff --git a/app.css b/src/app.css similarity index 100% rename from app.css rename to src/app.css diff --git a/app.d.ts b/src/app.d.ts similarity index 100% rename from app.d.ts rename to src/app.d.ts diff --git a/app.html b/src/app.html similarity index 100% rename from app.html rename to src/app.html diff --git a/hooks.server.ts b/src/hooks.server.ts similarity index 100% rename from hooks.server.ts rename to src/hooks.server.ts diff --git a/images/logo.webp b/src/images/logo.webp similarity index 100% rename from images/logo.webp rename to src/images/logo.webp diff --git a/lib/actions/column-resize.ts b/src/lib/actions/column-resize.ts similarity index 100% rename from lib/actions/column-resize.ts rename to src/lib/actions/column-resize.ts diff --git a/lib/assets/favicon.svg b/src/lib/assets/favicon.svg similarity index 100% rename from lib/assets/favicon.svg rename to src/lib/assets/favicon.svg diff --git a/lib/components/AvatarCropper.svelte b/src/lib/components/AvatarCropper.svelte similarity index 100% rename from lib/components/AvatarCropper.svelte rename to src/lib/components/AvatarCropper.svelte diff --git a/lib/components/BatchOperationModal.svelte b/src/lib/components/BatchOperationModal.svelte similarity index 100% rename from lib/components/BatchOperationModal.svelte rename to src/lib/components/BatchOperationModal.svelte diff --git a/lib/components/CodeEditor.svelte b/src/lib/components/CodeEditor.svelte similarity index 100% rename from lib/components/CodeEditor.svelte rename to src/lib/components/CodeEditor.svelte diff --git a/lib/components/ColumnSettingsPopover.svelte b/src/lib/components/ColumnSettingsPopover.svelte similarity index 100% rename from lib/components/ColumnSettingsPopover.svelte rename to src/lib/components/ColumnSettingsPopover.svelte diff --git a/lib/components/CommandPalette.svelte b/src/lib/components/CommandPalette.svelte similarity index 100% rename from lib/components/CommandPalette.svelte rename to src/lib/components/CommandPalette.svelte diff --git a/lib/components/ConfirmPopover.svelte b/src/lib/components/ConfirmPopover.svelte similarity index 100% rename from lib/components/ConfirmPopover.svelte rename to src/lib/components/ConfirmPopover.svelte diff --git a/lib/components/ExecutionLogViewer.svelte b/src/lib/components/ExecutionLogViewer.svelte similarity index 100% rename from lib/components/ExecutionLogViewer.svelte rename to src/lib/components/ExecutionLogViewer.svelte diff --git a/lib/components/MultiSelectFilter.svelte b/src/lib/components/MultiSelectFilter.svelte similarity index 100% rename from lib/components/MultiSelectFilter.svelte rename to src/lib/components/MultiSelectFilter.svelte diff --git a/lib/components/PageHeader.svelte b/src/lib/components/PageHeader.svelte similarity index 100% rename from lib/components/PageHeader.svelte rename to src/lib/components/PageHeader.svelte diff --git a/lib/components/PasswordStrengthIndicator.svelte b/src/lib/components/PasswordStrengthIndicator.svelte similarity index 100% rename from lib/components/PasswordStrengthIndicator.svelte rename to src/lib/components/PasswordStrengthIndicator.svelte diff --git a/lib/components/PullTab.svelte b/src/lib/components/PullTab.svelte similarity index 100% rename from lib/components/PullTab.svelte rename to src/lib/components/PullTab.svelte diff --git a/lib/components/PushTab.svelte b/src/lib/components/PushTab.svelte similarity index 100% rename from lib/components/PushTab.svelte rename to src/lib/components/PushTab.svelte diff --git a/lib/components/ScanTab.svelte b/src/lib/components/ScanTab.svelte similarity index 100% rename from lib/components/ScanTab.svelte rename to src/lib/components/ScanTab.svelte diff --git a/lib/components/ScannerSeverityPills.svelte b/src/lib/components/ScannerSeverityPills.svelte similarity index 100% rename from lib/components/ScannerSeverityPills.svelte rename to src/lib/components/ScannerSeverityPills.svelte diff --git a/lib/components/Sidebar.svelte b/src/lib/components/Sidebar.svelte similarity index 100% rename from lib/components/Sidebar.svelte rename to src/lib/components/Sidebar.svelte diff --git a/lib/components/StackEnvVarsEditor.svelte b/src/lib/components/StackEnvVarsEditor.svelte similarity index 100% rename from lib/components/StackEnvVarsEditor.svelte rename to src/lib/components/StackEnvVarsEditor.svelte diff --git a/lib/components/StackEnvVarsPanel.svelte b/src/lib/components/StackEnvVarsPanel.svelte similarity index 100% rename from lib/components/StackEnvVarsPanel.svelte rename to src/lib/components/StackEnvVarsPanel.svelte diff --git a/lib/components/ThemeSelector.svelte b/src/lib/components/ThemeSelector.svelte similarity index 100% rename from lib/components/ThemeSelector.svelte rename to src/lib/components/ThemeSelector.svelte diff --git a/lib/components/TimezoneSelector.svelte b/src/lib/components/TimezoneSelector.svelte similarity index 100% rename from lib/components/TimezoneSelector.svelte rename to src/lib/components/TimezoneSelector.svelte diff --git a/lib/components/UpdateContainerRow.svelte b/src/lib/components/UpdateContainerRow.svelte similarity index 100% rename from lib/components/UpdateContainerRow.svelte rename to src/lib/components/UpdateContainerRow.svelte diff --git a/lib/components/UpdateStepIndicator.svelte b/src/lib/components/UpdateStepIndicator.svelte similarity index 100% rename from lib/components/UpdateStepIndicator.svelte rename to src/lib/components/UpdateStepIndicator.svelte diff --git a/lib/components/UpdateSummaryStats.svelte b/src/lib/components/UpdateSummaryStats.svelte similarity index 100% rename from lib/components/UpdateSummaryStats.svelte rename to src/lib/components/UpdateSummaryStats.svelte diff --git a/lib/components/VulnerabilityCriteriaBadge.svelte b/src/lib/components/VulnerabilityCriteriaBadge.svelte similarity index 100% rename from lib/components/VulnerabilityCriteriaBadge.svelte rename to src/lib/components/VulnerabilityCriteriaBadge.svelte diff --git a/lib/components/VulnerabilityCriteriaSelector.svelte b/src/lib/components/VulnerabilityCriteriaSelector.svelte similarity index 100% rename from lib/components/VulnerabilityCriteriaSelector.svelte rename to src/lib/components/VulnerabilityCriteriaSelector.svelte diff --git a/lib/components/WhatsNewModal.svelte b/src/lib/components/WhatsNewModal.svelte similarity index 100% rename from lib/components/WhatsNewModal.svelte rename to src/lib/components/WhatsNewModal.svelte diff --git a/lib/components/app-sidebar.svelte b/src/lib/components/app-sidebar.svelte similarity index 100% rename from lib/components/app-sidebar.svelte rename to src/lib/components/app-sidebar.svelte diff --git a/lib/components/cron-editor.svelte b/src/lib/components/cron-editor.svelte similarity index 100% rename from lib/components/cron-editor.svelte rename to src/lib/components/cron-editor.svelte diff --git a/lib/components/data-grid/DataGrid.svelte b/src/lib/components/data-grid/DataGrid.svelte similarity index 100% rename from lib/components/data-grid/DataGrid.svelte rename to src/lib/components/data-grid/DataGrid.svelte diff --git a/lib/components/data-grid/context.ts b/src/lib/components/data-grid/context.ts similarity index 100% rename from lib/components/data-grid/context.ts rename to src/lib/components/data-grid/context.ts diff --git a/lib/components/data-grid/index.ts b/src/lib/components/data-grid/index.ts similarity index 100% rename from lib/components/data-grid/index.ts rename to src/lib/components/data-grid/index.ts diff --git a/lib/components/data-grid/types.ts b/src/lib/components/data-grid/types.ts similarity index 100% rename from lib/components/data-grid/types.ts rename to src/lib/components/data-grid/types.ts diff --git a/lib/components/host-info.svelte b/src/lib/components/host-info.svelte similarity index 100% rename from lib/components/host-info.svelte rename to src/lib/components/host-info.svelte diff --git a/lib/components/icon-picker.svelte b/src/lib/components/icon-picker.svelte similarity index 100% rename from lib/components/icon-picker.svelte rename to src/lib/components/icon-picker.svelte diff --git a/lib/components/main-content.svelte b/src/lib/components/main-content.svelte similarity index 100% rename from lib/components/main-content.svelte rename to src/lib/components/main-content.svelte diff --git a/lib/components/permission-guard.svelte b/src/lib/components/permission-guard.svelte similarity index 100% rename from lib/components/permission-guard.svelte rename to src/lib/components/permission-guard.svelte diff --git a/lib/components/theme-toggle.svelte b/src/lib/components/theme-toggle.svelte similarity index 100% rename from lib/components/theme-toggle.svelte rename to src/lib/components/theme-toggle.svelte diff --git a/lib/components/ui/accordion/accordion-content.svelte b/src/lib/components/ui/accordion/accordion-content.svelte similarity index 100% rename from lib/components/ui/accordion/accordion-content.svelte rename to src/lib/components/ui/accordion/accordion-content.svelte diff --git a/lib/components/ui/accordion/accordion-item.svelte b/src/lib/components/ui/accordion/accordion-item.svelte similarity index 100% rename from lib/components/ui/accordion/accordion-item.svelte rename to src/lib/components/ui/accordion/accordion-item.svelte diff --git a/lib/components/ui/accordion/accordion-trigger.svelte b/src/lib/components/ui/accordion/accordion-trigger.svelte similarity index 100% rename from lib/components/ui/accordion/accordion-trigger.svelte rename to src/lib/components/ui/accordion/accordion-trigger.svelte diff --git a/lib/components/ui/accordion/accordion.svelte b/src/lib/components/ui/accordion/accordion.svelte similarity index 100% rename from lib/components/ui/accordion/accordion.svelte rename to src/lib/components/ui/accordion/accordion.svelte diff --git a/lib/components/ui/accordion/index.ts b/src/lib/components/ui/accordion/index.ts similarity index 100% rename from lib/components/ui/accordion/index.ts rename to src/lib/components/ui/accordion/index.ts diff --git a/lib/components/ui/alert/alert-description.svelte b/src/lib/components/ui/alert/alert-description.svelte similarity index 100% rename from lib/components/ui/alert/alert-description.svelte rename to src/lib/components/ui/alert/alert-description.svelte diff --git a/lib/components/ui/alert/alert-title.svelte b/src/lib/components/ui/alert/alert-title.svelte similarity index 100% rename from lib/components/ui/alert/alert-title.svelte rename to src/lib/components/ui/alert/alert-title.svelte diff --git a/lib/components/ui/alert/alert.svelte b/src/lib/components/ui/alert/alert.svelte similarity index 100% rename from lib/components/ui/alert/alert.svelte rename to src/lib/components/ui/alert/alert.svelte diff --git a/lib/components/ui/alert/index.ts b/src/lib/components/ui/alert/index.ts similarity index 100% rename from lib/components/ui/alert/index.ts rename to src/lib/components/ui/alert/index.ts diff --git a/lib/components/ui/avatar/avatar-fallback.svelte b/src/lib/components/ui/avatar/avatar-fallback.svelte similarity index 100% rename from lib/components/ui/avatar/avatar-fallback.svelte rename to src/lib/components/ui/avatar/avatar-fallback.svelte diff --git a/lib/components/ui/avatar/avatar-image.svelte b/src/lib/components/ui/avatar/avatar-image.svelte similarity index 100% rename from lib/components/ui/avatar/avatar-image.svelte rename to src/lib/components/ui/avatar/avatar-image.svelte diff --git a/lib/components/ui/avatar/avatar.svelte b/src/lib/components/ui/avatar/avatar.svelte similarity index 100% rename from lib/components/ui/avatar/avatar.svelte rename to src/lib/components/ui/avatar/avatar.svelte diff --git a/lib/components/ui/avatar/index.ts b/src/lib/components/ui/avatar/index.ts similarity index 100% rename from lib/components/ui/avatar/index.ts rename to src/lib/components/ui/avatar/index.ts diff --git a/lib/components/ui/badge/badge.svelte b/src/lib/components/ui/badge/badge.svelte similarity index 100% rename from lib/components/ui/badge/badge.svelte rename to src/lib/components/ui/badge/badge.svelte diff --git a/lib/components/ui/badge/index.ts b/src/lib/components/ui/badge/index.ts similarity index 100% rename from lib/components/ui/badge/index.ts rename to src/lib/components/ui/badge/index.ts diff --git a/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte similarity index 100% rename from lib/components/ui/button/button.svelte rename to src/lib/components/ui/button/button.svelte diff --git a/lib/components/ui/button/index.ts b/src/lib/components/ui/button/index.ts similarity index 100% rename from lib/components/ui/button/index.ts rename to src/lib/components/ui/button/index.ts diff --git a/lib/components/ui/calendar/calendar-caption.svelte b/src/lib/components/ui/calendar/calendar-caption.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-caption.svelte rename to src/lib/components/ui/calendar/calendar-caption.svelte diff --git a/lib/components/ui/calendar/calendar-cell.svelte b/src/lib/components/ui/calendar/calendar-cell.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-cell.svelte rename to src/lib/components/ui/calendar/calendar-cell.svelte diff --git a/lib/components/ui/calendar/calendar-day.svelte b/src/lib/components/ui/calendar/calendar-day.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-day.svelte rename to src/lib/components/ui/calendar/calendar-day.svelte diff --git a/lib/components/ui/calendar/calendar-grid-body.svelte b/src/lib/components/ui/calendar/calendar-grid-body.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-grid-body.svelte rename to src/lib/components/ui/calendar/calendar-grid-body.svelte diff --git a/lib/components/ui/calendar/calendar-grid-head.svelte b/src/lib/components/ui/calendar/calendar-grid-head.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-grid-head.svelte rename to src/lib/components/ui/calendar/calendar-grid-head.svelte diff --git a/lib/components/ui/calendar/calendar-grid-row.svelte b/src/lib/components/ui/calendar/calendar-grid-row.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-grid-row.svelte rename to src/lib/components/ui/calendar/calendar-grid-row.svelte diff --git a/lib/components/ui/calendar/calendar-grid.svelte b/src/lib/components/ui/calendar/calendar-grid.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-grid.svelte rename to src/lib/components/ui/calendar/calendar-grid.svelte diff --git a/lib/components/ui/calendar/calendar-head-cell.svelte b/src/lib/components/ui/calendar/calendar-head-cell.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-head-cell.svelte rename to src/lib/components/ui/calendar/calendar-head-cell.svelte diff --git a/lib/components/ui/calendar/calendar-header.svelte b/src/lib/components/ui/calendar/calendar-header.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-header.svelte rename to src/lib/components/ui/calendar/calendar-header.svelte diff --git a/lib/components/ui/calendar/calendar-heading.svelte b/src/lib/components/ui/calendar/calendar-heading.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-heading.svelte rename to src/lib/components/ui/calendar/calendar-heading.svelte diff --git a/lib/components/ui/calendar/calendar-month-select.svelte b/src/lib/components/ui/calendar/calendar-month-select.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-month-select.svelte rename to src/lib/components/ui/calendar/calendar-month-select.svelte diff --git a/lib/components/ui/calendar/calendar-month.svelte b/src/lib/components/ui/calendar/calendar-month.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-month.svelte rename to src/lib/components/ui/calendar/calendar-month.svelte diff --git a/lib/components/ui/calendar/calendar-months.svelte b/src/lib/components/ui/calendar/calendar-months.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-months.svelte rename to src/lib/components/ui/calendar/calendar-months.svelte diff --git a/lib/components/ui/calendar/calendar-nav.svelte b/src/lib/components/ui/calendar/calendar-nav.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-nav.svelte rename to src/lib/components/ui/calendar/calendar-nav.svelte diff --git a/lib/components/ui/calendar/calendar-next-button.svelte b/src/lib/components/ui/calendar/calendar-next-button.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-next-button.svelte rename to src/lib/components/ui/calendar/calendar-next-button.svelte diff --git a/lib/components/ui/calendar/calendar-prev-button.svelte b/src/lib/components/ui/calendar/calendar-prev-button.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-prev-button.svelte rename to src/lib/components/ui/calendar/calendar-prev-button.svelte diff --git a/lib/components/ui/calendar/calendar-year-select.svelte b/src/lib/components/ui/calendar/calendar-year-select.svelte similarity index 100% rename from lib/components/ui/calendar/calendar-year-select.svelte rename to src/lib/components/ui/calendar/calendar-year-select.svelte diff --git a/lib/components/ui/calendar/calendar.svelte b/src/lib/components/ui/calendar/calendar.svelte similarity index 100% rename from lib/components/ui/calendar/calendar.svelte rename to src/lib/components/ui/calendar/calendar.svelte diff --git a/lib/components/ui/calendar/index.ts b/src/lib/components/ui/calendar/index.ts similarity index 100% rename from lib/components/ui/calendar/index.ts rename to src/lib/components/ui/calendar/index.ts diff --git a/lib/components/ui/card/card-action.svelte b/src/lib/components/ui/card/card-action.svelte similarity index 100% rename from lib/components/ui/card/card-action.svelte rename to src/lib/components/ui/card/card-action.svelte diff --git a/lib/components/ui/card/card-content.svelte b/src/lib/components/ui/card/card-content.svelte similarity index 100% rename from lib/components/ui/card/card-content.svelte rename to src/lib/components/ui/card/card-content.svelte diff --git a/lib/components/ui/card/card-description.svelte b/src/lib/components/ui/card/card-description.svelte similarity index 100% rename from lib/components/ui/card/card-description.svelte rename to src/lib/components/ui/card/card-description.svelte diff --git a/lib/components/ui/card/card-footer.svelte b/src/lib/components/ui/card/card-footer.svelte similarity index 100% rename from lib/components/ui/card/card-footer.svelte rename to src/lib/components/ui/card/card-footer.svelte diff --git a/lib/components/ui/card/card-header.svelte b/src/lib/components/ui/card/card-header.svelte similarity index 100% rename from lib/components/ui/card/card-header.svelte rename to src/lib/components/ui/card/card-header.svelte diff --git a/lib/components/ui/card/card-title.svelte b/src/lib/components/ui/card/card-title.svelte similarity index 100% rename from lib/components/ui/card/card-title.svelte rename to src/lib/components/ui/card/card-title.svelte diff --git a/lib/components/ui/card/card.svelte b/src/lib/components/ui/card/card.svelte similarity index 100% rename from lib/components/ui/card/card.svelte rename to src/lib/components/ui/card/card.svelte diff --git a/lib/components/ui/card/index.ts b/src/lib/components/ui/card/index.ts similarity index 100% rename from lib/components/ui/card/index.ts rename to src/lib/components/ui/card/index.ts diff --git a/lib/components/ui/checkbox/checkbox.svelte b/src/lib/components/ui/checkbox/checkbox.svelte similarity index 100% rename from lib/components/ui/checkbox/checkbox.svelte rename to src/lib/components/ui/checkbox/checkbox.svelte diff --git a/lib/components/ui/checkbox/index.ts b/src/lib/components/ui/checkbox/index.ts similarity index 100% rename from lib/components/ui/checkbox/index.ts rename to src/lib/components/ui/checkbox/index.ts diff --git a/lib/components/ui/command/command-dialog.svelte b/src/lib/components/ui/command/command-dialog.svelte similarity index 100% rename from lib/components/ui/command/command-dialog.svelte rename to src/lib/components/ui/command/command-dialog.svelte diff --git a/lib/components/ui/command/command-empty.svelte b/src/lib/components/ui/command/command-empty.svelte similarity index 100% rename from lib/components/ui/command/command-empty.svelte rename to src/lib/components/ui/command/command-empty.svelte diff --git a/lib/components/ui/command/command-group.svelte b/src/lib/components/ui/command/command-group.svelte similarity index 100% rename from lib/components/ui/command/command-group.svelte rename to src/lib/components/ui/command/command-group.svelte diff --git a/lib/components/ui/command/command-input.svelte b/src/lib/components/ui/command/command-input.svelte similarity index 100% rename from lib/components/ui/command/command-input.svelte rename to src/lib/components/ui/command/command-input.svelte diff --git a/lib/components/ui/command/command-item.svelte b/src/lib/components/ui/command/command-item.svelte similarity index 100% rename from lib/components/ui/command/command-item.svelte rename to src/lib/components/ui/command/command-item.svelte diff --git a/lib/components/ui/command/command-link-item.svelte b/src/lib/components/ui/command/command-link-item.svelte similarity index 100% rename from lib/components/ui/command/command-link-item.svelte rename to src/lib/components/ui/command/command-link-item.svelte diff --git a/lib/components/ui/command/command-list.svelte b/src/lib/components/ui/command/command-list.svelte similarity index 100% rename from lib/components/ui/command/command-list.svelte rename to src/lib/components/ui/command/command-list.svelte diff --git a/lib/components/ui/command/command-loading.svelte b/src/lib/components/ui/command/command-loading.svelte similarity index 100% rename from lib/components/ui/command/command-loading.svelte rename to src/lib/components/ui/command/command-loading.svelte diff --git a/lib/components/ui/command/command-separator.svelte b/src/lib/components/ui/command/command-separator.svelte similarity index 100% rename from lib/components/ui/command/command-separator.svelte rename to src/lib/components/ui/command/command-separator.svelte diff --git a/lib/components/ui/command/command-shortcut.svelte b/src/lib/components/ui/command/command-shortcut.svelte similarity index 100% rename from lib/components/ui/command/command-shortcut.svelte rename to src/lib/components/ui/command/command-shortcut.svelte diff --git a/lib/components/ui/command/command.svelte b/src/lib/components/ui/command/command.svelte similarity index 100% rename from lib/components/ui/command/command.svelte rename to src/lib/components/ui/command/command.svelte diff --git a/lib/components/ui/command/index.ts b/src/lib/components/ui/command/index.ts similarity index 100% rename from lib/components/ui/command/index.ts rename to src/lib/components/ui/command/index.ts diff --git a/lib/components/ui/date-picker/date-picker.svelte b/src/lib/components/ui/date-picker/date-picker.svelte similarity index 100% rename from lib/components/ui/date-picker/date-picker.svelte rename to src/lib/components/ui/date-picker/date-picker.svelte diff --git a/lib/components/ui/date-picker/index.ts b/src/lib/components/ui/date-picker/index.ts similarity index 100% rename from lib/components/ui/date-picker/index.ts rename to src/lib/components/ui/date-picker/index.ts diff --git a/lib/components/ui/dialog/dialog-close.svelte b/src/lib/components/ui/dialog/dialog-close.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-close.svelte rename to src/lib/components/ui/dialog/dialog-close.svelte diff --git a/lib/components/ui/dialog/dialog-content.svelte b/src/lib/components/ui/dialog/dialog-content.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-content.svelte rename to src/lib/components/ui/dialog/dialog-content.svelte diff --git a/lib/components/ui/dialog/dialog-description.svelte b/src/lib/components/ui/dialog/dialog-description.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-description.svelte rename to src/lib/components/ui/dialog/dialog-description.svelte diff --git a/lib/components/ui/dialog/dialog-footer.svelte b/src/lib/components/ui/dialog/dialog-footer.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-footer.svelte rename to src/lib/components/ui/dialog/dialog-footer.svelte diff --git a/lib/components/ui/dialog/dialog-header.svelte b/src/lib/components/ui/dialog/dialog-header.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-header.svelte rename to src/lib/components/ui/dialog/dialog-header.svelte diff --git a/lib/components/ui/dialog/dialog-overlay.svelte b/src/lib/components/ui/dialog/dialog-overlay.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-overlay.svelte rename to src/lib/components/ui/dialog/dialog-overlay.svelte diff --git a/lib/components/ui/dialog/dialog-portal.svelte b/src/lib/components/ui/dialog/dialog-portal.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-portal.svelte rename to src/lib/components/ui/dialog/dialog-portal.svelte diff --git a/lib/components/ui/dialog/dialog-title.svelte b/src/lib/components/ui/dialog/dialog-title.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-title.svelte rename to src/lib/components/ui/dialog/dialog-title.svelte diff --git a/lib/components/ui/dialog/dialog-trigger.svelte b/src/lib/components/ui/dialog/dialog-trigger.svelte similarity index 100% rename from lib/components/ui/dialog/dialog-trigger.svelte rename to src/lib/components/ui/dialog/dialog-trigger.svelte diff --git a/lib/components/ui/dialog/dialog.svelte b/src/lib/components/ui/dialog/dialog.svelte similarity index 100% rename from lib/components/ui/dialog/dialog.svelte rename to src/lib/components/ui/dialog/dialog.svelte diff --git a/lib/components/ui/dialog/index.ts b/src/lib/components/ui/dialog/index.ts similarity index 100% rename from lib/components/ui/dialog/index.ts rename to src/lib/components/ui/dialog/index.ts diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-group.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-content.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-group.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-group.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-item.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-label.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-portal.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-sub.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu-trigger.svelte diff --git a/lib/components/ui/dropdown-menu/dropdown-menu.svelte b/src/lib/components/ui/dropdown-menu/dropdown-menu.svelte similarity index 100% rename from lib/components/ui/dropdown-menu/dropdown-menu.svelte rename to src/lib/components/ui/dropdown-menu/dropdown-menu.svelte diff --git a/lib/components/ui/dropdown-menu/index.ts b/src/lib/components/ui/dropdown-menu/index.ts similarity index 100% rename from lib/components/ui/dropdown-menu/index.ts rename to src/lib/components/ui/dropdown-menu/index.ts diff --git a/lib/components/ui/empty-state/empty-state.svelte b/src/lib/components/ui/empty-state/empty-state.svelte similarity index 100% rename from lib/components/ui/empty-state/empty-state.svelte rename to src/lib/components/ui/empty-state/empty-state.svelte diff --git a/lib/components/ui/empty-state/index.ts b/src/lib/components/ui/empty-state/index.ts similarity index 100% rename from lib/components/ui/empty-state/index.ts rename to src/lib/components/ui/empty-state/index.ts diff --git a/lib/components/ui/empty-state/no-environment.svelte b/src/lib/components/ui/empty-state/no-environment.svelte similarity index 100% rename from lib/components/ui/empty-state/no-environment.svelte rename to src/lib/components/ui/empty-state/no-environment.svelte diff --git a/lib/components/ui/input/index.ts b/src/lib/components/ui/input/index.ts similarity index 100% rename from lib/components/ui/input/index.ts rename to src/lib/components/ui/input/index.ts diff --git a/lib/components/ui/input/input.svelte b/src/lib/components/ui/input/input.svelte similarity index 100% rename from lib/components/ui/input/input.svelte rename to src/lib/components/ui/input/input.svelte diff --git a/lib/components/ui/label/index.ts b/src/lib/components/ui/label/index.ts similarity index 100% rename from lib/components/ui/label/index.ts rename to src/lib/components/ui/label/index.ts diff --git a/lib/components/ui/label/label.svelte b/src/lib/components/ui/label/label.svelte similarity index 100% rename from lib/components/ui/label/label.svelte rename to src/lib/components/ui/label/label.svelte diff --git a/lib/components/ui/popover/index.ts b/src/lib/components/ui/popover/index.ts similarity index 100% rename from lib/components/ui/popover/index.ts rename to src/lib/components/ui/popover/index.ts diff --git a/lib/components/ui/popover/popover-content.svelte b/src/lib/components/ui/popover/popover-content.svelte similarity index 100% rename from lib/components/ui/popover/popover-content.svelte rename to src/lib/components/ui/popover/popover-content.svelte diff --git a/lib/components/ui/popover/popover-trigger.svelte b/src/lib/components/ui/popover/popover-trigger.svelte similarity index 100% rename from lib/components/ui/popover/popover-trigger.svelte rename to src/lib/components/ui/popover/popover-trigger.svelte diff --git a/lib/components/ui/progress/index.ts b/src/lib/components/ui/progress/index.ts similarity index 100% rename from lib/components/ui/progress/index.ts rename to src/lib/components/ui/progress/index.ts diff --git a/lib/components/ui/progress/progress.svelte b/src/lib/components/ui/progress/progress.svelte similarity index 100% rename from lib/components/ui/progress/progress.svelte rename to src/lib/components/ui/progress/progress.svelte diff --git a/lib/components/ui/select/index.ts b/src/lib/components/ui/select/index.ts similarity index 100% rename from lib/components/ui/select/index.ts rename to src/lib/components/ui/select/index.ts diff --git a/lib/components/ui/select/select-content.svelte b/src/lib/components/ui/select/select-content.svelte similarity index 100% rename from lib/components/ui/select/select-content.svelte rename to src/lib/components/ui/select/select-content.svelte diff --git a/lib/components/ui/select/select-group-heading.svelte b/src/lib/components/ui/select/select-group-heading.svelte similarity index 100% rename from lib/components/ui/select/select-group-heading.svelte rename to src/lib/components/ui/select/select-group-heading.svelte diff --git a/lib/components/ui/select/select-group.svelte b/src/lib/components/ui/select/select-group.svelte similarity index 100% rename from lib/components/ui/select/select-group.svelte rename to src/lib/components/ui/select/select-group.svelte diff --git a/lib/components/ui/select/select-item.svelte b/src/lib/components/ui/select/select-item.svelte similarity index 100% rename from lib/components/ui/select/select-item.svelte rename to src/lib/components/ui/select/select-item.svelte diff --git a/lib/components/ui/select/select-label.svelte b/src/lib/components/ui/select/select-label.svelte similarity index 100% rename from lib/components/ui/select/select-label.svelte rename to src/lib/components/ui/select/select-label.svelte diff --git a/lib/components/ui/select/select-scroll-down-button.svelte b/src/lib/components/ui/select/select-scroll-down-button.svelte similarity index 100% rename from lib/components/ui/select/select-scroll-down-button.svelte rename to src/lib/components/ui/select/select-scroll-down-button.svelte diff --git a/lib/components/ui/select/select-scroll-up-button.svelte b/src/lib/components/ui/select/select-scroll-up-button.svelte similarity index 100% rename from lib/components/ui/select/select-scroll-up-button.svelte rename to src/lib/components/ui/select/select-scroll-up-button.svelte diff --git a/lib/components/ui/select/select-separator.svelte b/src/lib/components/ui/select/select-separator.svelte similarity index 100% rename from lib/components/ui/select/select-separator.svelte rename to src/lib/components/ui/select/select-separator.svelte diff --git a/lib/components/ui/select/select-trigger.svelte b/src/lib/components/ui/select/select-trigger.svelte similarity index 100% rename from lib/components/ui/select/select-trigger.svelte rename to src/lib/components/ui/select/select-trigger.svelte diff --git a/lib/components/ui/separator/index.ts b/src/lib/components/ui/separator/index.ts similarity index 100% rename from lib/components/ui/separator/index.ts rename to src/lib/components/ui/separator/index.ts diff --git a/lib/components/ui/separator/separator.svelte b/src/lib/components/ui/separator/separator.svelte similarity index 100% rename from lib/components/ui/separator/separator.svelte rename to src/lib/components/ui/separator/separator.svelte diff --git a/lib/components/ui/sheet/index.ts b/src/lib/components/ui/sheet/index.ts similarity index 100% rename from lib/components/ui/sheet/index.ts rename to src/lib/components/ui/sheet/index.ts diff --git a/lib/components/ui/sheet/sheet-close.svelte b/src/lib/components/ui/sheet/sheet-close.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-close.svelte rename to src/lib/components/ui/sheet/sheet-close.svelte diff --git a/lib/components/ui/sheet/sheet-content.svelte b/src/lib/components/ui/sheet/sheet-content.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-content.svelte rename to src/lib/components/ui/sheet/sheet-content.svelte diff --git a/lib/components/ui/sheet/sheet-description.svelte b/src/lib/components/ui/sheet/sheet-description.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-description.svelte rename to src/lib/components/ui/sheet/sheet-description.svelte diff --git a/lib/components/ui/sheet/sheet-footer.svelte b/src/lib/components/ui/sheet/sheet-footer.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-footer.svelte rename to src/lib/components/ui/sheet/sheet-footer.svelte diff --git a/lib/components/ui/sheet/sheet-header.svelte b/src/lib/components/ui/sheet/sheet-header.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-header.svelte rename to src/lib/components/ui/sheet/sheet-header.svelte diff --git a/lib/components/ui/sheet/sheet-overlay.svelte b/src/lib/components/ui/sheet/sheet-overlay.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-overlay.svelte rename to src/lib/components/ui/sheet/sheet-overlay.svelte diff --git a/lib/components/ui/sheet/sheet-title.svelte b/src/lib/components/ui/sheet/sheet-title.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-title.svelte rename to src/lib/components/ui/sheet/sheet-title.svelte diff --git a/lib/components/ui/sheet/sheet-trigger.svelte b/src/lib/components/ui/sheet/sheet-trigger.svelte similarity index 100% rename from lib/components/ui/sheet/sheet-trigger.svelte rename to src/lib/components/ui/sheet/sheet-trigger.svelte diff --git a/lib/components/ui/sidebar/constants.ts b/src/lib/components/ui/sidebar/constants.ts similarity index 100% rename from lib/components/ui/sidebar/constants.ts rename to src/lib/components/ui/sidebar/constants.ts diff --git a/lib/components/ui/sidebar/context.svelte.ts b/src/lib/components/ui/sidebar/context.svelte.ts similarity index 100% rename from lib/components/ui/sidebar/context.svelte.ts rename to src/lib/components/ui/sidebar/context.svelte.ts diff --git a/lib/components/ui/sidebar/index.ts b/src/lib/components/ui/sidebar/index.ts similarity index 100% rename from lib/components/ui/sidebar/index.ts rename to src/lib/components/ui/sidebar/index.ts diff --git a/lib/components/ui/sidebar/sidebar-content.svelte b/src/lib/components/ui/sidebar/sidebar-content.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-content.svelte rename to src/lib/components/ui/sidebar/sidebar-content.svelte diff --git a/lib/components/ui/sidebar/sidebar-footer.svelte b/src/lib/components/ui/sidebar/sidebar-footer.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-footer.svelte rename to src/lib/components/ui/sidebar/sidebar-footer.svelte diff --git a/lib/components/ui/sidebar/sidebar-group-action.svelte b/src/lib/components/ui/sidebar/sidebar-group-action.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-group-action.svelte rename to src/lib/components/ui/sidebar/sidebar-group-action.svelte diff --git a/lib/components/ui/sidebar/sidebar-group-content.svelte b/src/lib/components/ui/sidebar/sidebar-group-content.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-group-content.svelte rename to src/lib/components/ui/sidebar/sidebar-group-content.svelte diff --git a/lib/components/ui/sidebar/sidebar-group-label.svelte b/src/lib/components/ui/sidebar/sidebar-group-label.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-group-label.svelte rename to src/lib/components/ui/sidebar/sidebar-group-label.svelte diff --git a/lib/components/ui/sidebar/sidebar-group.svelte b/src/lib/components/ui/sidebar/sidebar-group.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-group.svelte rename to src/lib/components/ui/sidebar/sidebar-group.svelte diff --git a/lib/components/ui/sidebar/sidebar-header.svelte b/src/lib/components/ui/sidebar/sidebar-header.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-header.svelte rename to src/lib/components/ui/sidebar/sidebar-header.svelte diff --git a/lib/components/ui/sidebar/sidebar-input.svelte b/src/lib/components/ui/sidebar/sidebar-input.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-input.svelte rename to src/lib/components/ui/sidebar/sidebar-input.svelte diff --git a/lib/components/ui/sidebar/sidebar-inset.svelte b/src/lib/components/ui/sidebar/sidebar-inset.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-inset.svelte rename to src/lib/components/ui/sidebar/sidebar-inset.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-action.svelte b/src/lib/components/ui/sidebar/sidebar-menu-action.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-action.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-action.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-badge.svelte b/src/lib/components/ui/sidebar/sidebar-menu-badge.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-badge.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-badge.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-button.svelte b/src/lib/components/ui/sidebar/sidebar-menu-button.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-button.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-button.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-item.svelte b/src/lib/components/ui/sidebar/sidebar-menu-item.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-item.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-item.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte b/src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-skeleton.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-skeleton.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte b/src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-sub-button.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-sub-button.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte b/src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-sub-item.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-sub-item.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu-sub.svelte b/src/lib/components/ui/sidebar/sidebar-menu-sub.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu-sub.svelte rename to src/lib/components/ui/sidebar/sidebar-menu-sub.svelte diff --git a/lib/components/ui/sidebar/sidebar-menu.svelte b/src/lib/components/ui/sidebar/sidebar-menu.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-menu.svelte rename to src/lib/components/ui/sidebar/sidebar-menu.svelte diff --git a/lib/components/ui/sidebar/sidebar-provider.svelte b/src/lib/components/ui/sidebar/sidebar-provider.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-provider.svelte rename to src/lib/components/ui/sidebar/sidebar-provider.svelte diff --git a/lib/components/ui/sidebar/sidebar-rail.svelte b/src/lib/components/ui/sidebar/sidebar-rail.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-rail.svelte rename to src/lib/components/ui/sidebar/sidebar-rail.svelte diff --git a/lib/components/ui/sidebar/sidebar-separator.svelte b/src/lib/components/ui/sidebar/sidebar-separator.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-separator.svelte rename to src/lib/components/ui/sidebar/sidebar-separator.svelte diff --git a/lib/components/ui/sidebar/sidebar-trigger.svelte b/src/lib/components/ui/sidebar/sidebar-trigger.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar-trigger.svelte rename to src/lib/components/ui/sidebar/sidebar-trigger.svelte diff --git a/lib/components/ui/sidebar/sidebar.svelte b/src/lib/components/ui/sidebar/sidebar.svelte similarity index 100% rename from lib/components/ui/sidebar/sidebar.svelte rename to src/lib/components/ui/sidebar/sidebar.svelte diff --git a/lib/components/ui/skeleton/index.ts b/src/lib/components/ui/skeleton/index.ts similarity index 100% rename from lib/components/ui/skeleton/index.ts rename to src/lib/components/ui/skeleton/index.ts diff --git a/lib/components/ui/skeleton/skeleton.svelte b/src/lib/components/ui/skeleton/skeleton.svelte similarity index 100% rename from lib/components/ui/skeleton/skeleton.svelte rename to src/lib/components/ui/skeleton/skeleton.svelte diff --git a/lib/components/ui/sonner/index.ts b/src/lib/components/ui/sonner/index.ts similarity index 100% rename from lib/components/ui/sonner/index.ts rename to src/lib/components/ui/sonner/index.ts diff --git a/lib/components/ui/sonner/sonner.svelte b/src/lib/components/ui/sonner/sonner.svelte similarity index 100% rename from lib/components/ui/sonner/sonner.svelte rename to src/lib/components/ui/sonner/sonner.svelte diff --git a/lib/components/ui/switch/index.ts b/src/lib/components/ui/switch/index.ts similarity index 100% rename from lib/components/ui/switch/index.ts rename to src/lib/components/ui/switch/index.ts diff --git a/lib/components/ui/switch/switch.svelte b/src/lib/components/ui/switch/switch.svelte similarity index 100% rename from lib/components/ui/switch/switch.svelte rename to src/lib/components/ui/switch/switch.svelte diff --git a/lib/components/ui/table/index.ts b/src/lib/components/ui/table/index.ts similarity index 100% rename from lib/components/ui/table/index.ts rename to src/lib/components/ui/table/index.ts diff --git a/lib/components/ui/table/table-body.svelte b/src/lib/components/ui/table/table-body.svelte similarity index 100% rename from lib/components/ui/table/table-body.svelte rename to src/lib/components/ui/table/table-body.svelte diff --git a/lib/components/ui/table/table-caption.svelte b/src/lib/components/ui/table/table-caption.svelte similarity index 100% rename from lib/components/ui/table/table-caption.svelte rename to src/lib/components/ui/table/table-caption.svelte diff --git a/lib/components/ui/table/table-cell.svelte b/src/lib/components/ui/table/table-cell.svelte similarity index 100% rename from lib/components/ui/table/table-cell.svelte rename to src/lib/components/ui/table/table-cell.svelte diff --git a/lib/components/ui/table/table-footer.svelte b/src/lib/components/ui/table/table-footer.svelte similarity index 100% rename from lib/components/ui/table/table-footer.svelte rename to src/lib/components/ui/table/table-footer.svelte diff --git a/lib/components/ui/table/table-head.svelte b/src/lib/components/ui/table/table-head.svelte similarity index 100% rename from lib/components/ui/table/table-head.svelte rename to src/lib/components/ui/table/table-head.svelte diff --git a/lib/components/ui/table/table-header.svelte b/src/lib/components/ui/table/table-header.svelte similarity index 100% rename from lib/components/ui/table/table-header.svelte rename to src/lib/components/ui/table/table-header.svelte diff --git a/lib/components/ui/table/table-row.svelte b/src/lib/components/ui/table/table-row.svelte similarity index 100% rename from lib/components/ui/table/table-row.svelte rename to src/lib/components/ui/table/table-row.svelte diff --git a/lib/components/ui/table/table.svelte b/src/lib/components/ui/table/table.svelte similarity index 100% rename from lib/components/ui/table/table.svelte rename to src/lib/components/ui/table/table.svelte diff --git a/lib/components/ui/tabs/index.ts b/src/lib/components/ui/tabs/index.ts similarity index 100% rename from lib/components/ui/tabs/index.ts rename to src/lib/components/ui/tabs/index.ts diff --git a/lib/components/ui/tabs/tabs-content.svelte b/src/lib/components/ui/tabs/tabs-content.svelte similarity index 100% rename from lib/components/ui/tabs/tabs-content.svelte rename to src/lib/components/ui/tabs/tabs-content.svelte diff --git a/lib/components/ui/tabs/tabs-list.svelte b/src/lib/components/ui/tabs/tabs-list.svelte similarity index 100% rename from lib/components/ui/tabs/tabs-list.svelte rename to src/lib/components/ui/tabs/tabs-list.svelte diff --git a/lib/components/ui/tabs/tabs-trigger.svelte b/src/lib/components/ui/tabs/tabs-trigger.svelte similarity index 100% rename from lib/components/ui/tabs/tabs-trigger.svelte rename to src/lib/components/ui/tabs/tabs-trigger.svelte diff --git a/lib/components/ui/tabs/tabs.svelte b/src/lib/components/ui/tabs/tabs.svelte similarity index 100% rename from lib/components/ui/tabs/tabs.svelte rename to src/lib/components/ui/tabs/tabs.svelte diff --git a/lib/components/ui/textarea/index.ts b/src/lib/components/ui/textarea/index.ts similarity index 100% rename from lib/components/ui/textarea/index.ts rename to src/lib/components/ui/textarea/index.ts diff --git a/lib/components/ui/textarea/textarea.svelte b/src/lib/components/ui/textarea/textarea.svelte similarity index 100% rename from lib/components/ui/textarea/textarea.svelte rename to src/lib/components/ui/textarea/textarea.svelte diff --git a/lib/components/ui/toggle-pill/index.ts b/src/lib/components/ui/toggle-pill/index.ts similarity index 100% rename from lib/components/ui/toggle-pill/index.ts rename to src/lib/components/ui/toggle-pill/index.ts diff --git a/lib/components/ui/toggle-pill/toggle-group.svelte b/src/lib/components/ui/toggle-pill/toggle-group.svelte similarity index 100% rename from lib/components/ui/toggle-pill/toggle-group.svelte rename to src/lib/components/ui/toggle-pill/toggle-group.svelte diff --git a/lib/components/ui/toggle-pill/toggle-pill.svelte b/src/lib/components/ui/toggle-pill/toggle-pill.svelte similarity index 100% rename from lib/components/ui/toggle-pill/toggle-pill.svelte rename to src/lib/components/ui/toggle-pill/toggle-pill.svelte diff --git a/lib/components/ui/toggle-pill/toggle-switch.svelte b/src/lib/components/ui/toggle-pill/toggle-switch.svelte similarity index 100% rename from lib/components/ui/toggle-pill/toggle-switch.svelte rename to src/lib/components/ui/toggle-pill/toggle-switch.svelte diff --git a/lib/components/ui/tooltip/index.ts b/src/lib/components/ui/tooltip/index.ts similarity index 100% rename from lib/components/ui/tooltip/index.ts rename to src/lib/components/ui/tooltip/index.ts diff --git a/lib/components/ui/tooltip/tooltip-content.svelte b/src/lib/components/ui/tooltip/tooltip-content.svelte similarity index 100% rename from lib/components/ui/tooltip/tooltip-content.svelte rename to src/lib/components/ui/tooltip/tooltip-content.svelte diff --git a/lib/components/ui/tooltip/tooltip-trigger.svelte b/src/lib/components/ui/tooltip/tooltip-trigger.svelte similarity index 100% rename from lib/components/ui/tooltip/tooltip-trigger.svelte rename to src/lib/components/ui/tooltip/tooltip-trigger.svelte diff --git a/lib/config/grid-columns.ts b/src/lib/config/grid-columns.ts similarity index 100% rename from lib/config/grid-columns.ts rename to src/lib/config/grid-columns.ts diff --git a/lib/data/changelog.json b/src/lib/data/changelog.json similarity index 100% rename from lib/data/changelog.json rename to src/lib/data/changelog.json diff --git a/lib/data/dependencies.json b/src/lib/data/dependencies.json similarity index 100% rename from lib/data/dependencies.json rename to src/lib/data/dependencies.json diff --git a/lib/hooks/is-mobile.svelte.ts b/src/lib/hooks/is-mobile.svelte.ts similarity index 100% rename from lib/hooks/is-mobile.svelte.ts rename to src/lib/hooks/is-mobile.svelte.ts diff --git a/lib/index.ts b/src/lib/index.ts similarity index 100% rename from lib/index.ts rename to src/lib/index.ts diff --git a/lib/server/audit-events.ts b/src/lib/server/audit-events.ts similarity index 100% rename from lib/server/audit-events.ts rename to src/lib/server/audit-events.ts diff --git a/lib/server/audit.ts b/src/lib/server/audit.ts similarity index 100% rename from lib/server/audit.ts rename to src/lib/server/audit.ts diff --git a/lib/server/auth.ts b/src/lib/server/auth.ts similarity index 100% rename from lib/server/auth.ts rename to src/lib/server/auth.ts diff --git a/lib/server/authorize.ts b/src/lib/server/authorize.ts similarity index 100% rename from lib/server/authorize.ts rename to src/lib/server/authorize.ts diff --git a/lib/server/db.ts b/src/lib/server/db.ts similarity index 100% rename from lib/server/db.ts rename to src/lib/server/db.ts diff --git a/lib/server/db/connection.ts b/src/lib/server/db/connection.ts similarity index 100% rename from lib/server/db/connection.ts rename to src/lib/server/db/connection.ts diff --git a/lib/server/db/drizzle.ts b/src/lib/server/db/drizzle.ts similarity index 100% rename from lib/server/db/drizzle.ts rename to src/lib/server/db/drizzle.ts diff --git a/lib/server/db/schema/index.ts b/src/lib/server/db/schema/index.ts similarity index 100% rename from lib/server/db/schema/index.ts rename to src/lib/server/db/schema/index.ts diff --git a/lib/server/db/schema/pg-schema.ts b/src/lib/server/db/schema/pg-schema.ts similarity index 100% rename from lib/server/db/schema/pg-schema.ts rename to src/lib/server/db/schema/pg-schema.ts diff --git a/lib/server/docker.ts b/src/lib/server/docker.ts similarity index 100% rename from lib/server/docker.ts rename to src/lib/server/docker.ts diff --git a/lib/server/event-collector.ts b/src/lib/server/event-collector.ts similarity index 100% rename from lib/server/event-collector.ts rename to src/lib/server/event-collector.ts diff --git a/lib/server/git.ts b/src/lib/server/git.ts similarity index 100% rename from lib/server/git.ts rename to src/lib/server/git.ts diff --git a/lib/server/hawser.ts b/src/lib/server/hawser.ts similarity index 100% rename from lib/server/hawser.ts rename to src/lib/server/hawser.ts diff --git a/lib/server/license.ts b/src/lib/server/license.ts similarity index 100% rename from lib/server/license.ts rename to src/lib/server/license.ts diff --git a/lib/server/metrics-collector.ts b/src/lib/server/metrics-collector.ts similarity index 100% rename from lib/server/metrics-collector.ts rename to src/lib/server/metrics-collector.ts diff --git a/lib/server/notifications.ts b/src/lib/server/notifications.ts similarity index 100% rename from lib/server/notifications.ts rename to src/lib/server/notifications.ts diff --git a/lib/server/scanner.ts b/src/lib/server/scanner.ts similarity index 100% rename from lib/server/scanner.ts rename to src/lib/server/scanner.ts diff --git a/lib/server/scheduler/index.ts b/src/lib/server/scheduler/index.ts similarity index 100% rename from lib/server/scheduler/index.ts rename to src/lib/server/scheduler/index.ts diff --git a/lib/server/scheduler/tasks/container-update.ts b/src/lib/server/scheduler/tasks/container-update.ts similarity index 100% rename from lib/server/scheduler/tasks/container-update.ts rename to src/lib/server/scheduler/tasks/container-update.ts diff --git a/lib/server/scheduler/tasks/env-update-check.ts b/src/lib/server/scheduler/tasks/env-update-check.ts similarity index 100% rename from lib/server/scheduler/tasks/env-update-check.ts rename to src/lib/server/scheduler/tasks/env-update-check.ts diff --git a/lib/server/scheduler/tasks/git-stack-sync.ts b/src/lib/server/scheduler/tasks/git-stack-sync.ts similarity index 100% rename from lib/server/scheduler/tasks/git-stack-sync.ts rename to src/lib/server/scheduler/tasks/git-stack-sync.ts diff --git a/lib/server/scheduler/tasks/system-cleanup.ts b/src/lib/server/scheduler/tasks/system-cleanup.ts similarity index 100% rename from lib/server/scheduler/tasks/system-cleanup.ts rename to src/lib/server/scheduler/tasks/system-cleanup.ts diff --git a/lib/server/scheduler/tasks/update-utils.ts b/src/lib/server/scheduler/tasks/update-utils.ts similarity index 100% rename from lib/server/scheduler/tasks/update-utils.ts rename to src/lib/server/scheduler/tasks/update-utils.ts diff --git a/lib/server/stacks.ts b/src/lib/server/stacks.ts similarity index 100% rename from lib/server/stacks.ts rename to src/lib/server/stacks.ts diff --git a/lib/server/subprocess-manager.ts b/src/lib/server/subprocess-manager.ts similarity index 100% rename from lib/server/subprocess-manager.ts rename to src/lib/server/subprocess-manager.ts diff --git a/lib/server/subprocesses/event-subprocess.ts b/src/lib/server/subprocesses/event-subprocess.ts similarity index 100% rename from lib/server/subprocesses/event-subprocess.ts rename to src/lib/server/subprocesses/event-subprocess.ts diff --git a/lib/server/subprocesses/metrics-subprocess.ts b/src/lib/server/subprocesses/metrics-subprocess.ts similarity index 100% rename from lib/server/subprocesses/metrics-subprocess.ts rename to src/lib/server/subprocesses/metrics-subprocess.ts diff --git a/lib/server/uptime.ts b/src/lib/server/uptime.ts similarity index 100% rename from lib/server/uptime.ts rename to src/lib/server/uptime.ts diff --git a/lib/stores/audit-events.ts b/src/lib/stores/audit-events.ts similarity index 100% rename from lib/stores/audit-events.ts rename to src/lib/stores/audit-events.ts diff --git a/lib/stores/auth.ts b/src/lib/stores/auth.ts similarity index 100% rename from lib/stores/auth.ts rename to src/lib/stores/auth.ts diff --git a/lib/stores/dashboard.ts b/src/lib/stores/dashboard.ts similarity index 100% rename from lib/stores/dashboard.ts rename to src/lib/stores/dashboard.ts diff --git a/lib/stores/environment.ts b/src/lib/stores/environment.ts similarity index 100% rename from lib/stores/environment.ts rename to src/lib/stores/environment.ts diff --git a/lib/stores/events.ts b/src/lib/stores/events.ts similarity index 100% rename from lib/stores/events.ts rename to src/lib/stores/events.ts diff --git a/lib/stores/grid-preferences.ts b/src/lib/stores/grid-preferences.ts similarity index 100% rename from lib/stores/grid-preferences.ts rename to src/lib/stores/grid-preferences.ts diff --git a/lib/stores/license.ts b/src/lib/stores/license.ts similarity index 100% rename from lib/stores/license.ts rename to src/lib/stores/license.ts diff --git a/lib/stores/settings.ts b/src/lib/stores/settings.ts similarity index 100% rename from lib/stores/settings.ts rename to src/lib/stores/settings.ts diff --git a/lib/stores/stats.ts b/src/lib/stores/stats.ts similarity index 100% rename from lib/stores/stats.ts rename to src/lib/stores/stats.ts diff --git a/lib/stores/theme.ts b/src/lib/stores/theme.ts similarity index 100% rename from lib/stores/theme.ts rename to src/lib/stores/theme.ts diff --git a/lib/themes.ts b/src/lib/themes.ts similarity index 100% rename from lib/themes.ts rename to src/lib/themes.ts diff --git a/lib/types.ts b/src/lib/types.ts similarity index 100% rename from lib/types.ts rename to src/lib/types.ts diff --git a/lib/utils.ts b/src/lib/utils.ts similarity index 100% rename from lib/utils.ts rename to src/lib/utils.ts diff --git a/lib/utils/icons.ts b/src/lib/utils/icons.ts similarity index 100% rename from lib/utils/icons.ts rename to src/lib/utils/icons.ts diff --git a/lib/utils/ip.ts b/src/lib/utils/ip.ts similarity index 100% rename from lib/utils/ip.ts rename to src/lib/utils/ip.ts diff --git a/lib/utils/label-colors.ts b/src/lib/utils/label-colors.ts similarity index 100% rename from lib/utils/label-colors.ts rename to src/lib/utils/label-colors.ts diff --git a/lib/utils/update-steps.ts b/src/lib/utils/update-steps.ts similarity index 100% rename from lib/utils/update-steps.ts rename to src/lib/utils/update-steps.ts diff --git a/lib/utils/version.ts b/src/lib/utils/version.ts similarity index 100% rename from lib/utils/version.ts rename to src/lib/utils/version.ts diff --git a/routes/+layout.server.ts b/src/routes/+layout.server.ts similarity index 100% rename from routes/+layout.server.ts rename to src/routes/+layout.server.ts diff --git a/routes/+layout.svelte b/src/routes/+layout.svelte similarity index 100% rename from routes/+layout.svelte rename to src/routes/+layout.svelte diff --git a/routes/+layout.ts b/src/routes/+layout.ts similarity index 100% rename from routes/+layout.ts rename to src/routes/+layout.ts diff --git a/routes/+page.svelte b/src/routes/+page.svelte similarity index 100% rename from routes/+page.svelte rename to src/routes/+page.svelte diff --git a/routes/activity/+page.svelte b/src/routes/activity/+page.svelte similarity index 100% rename from routes/activity/+page.svelte rename to src/routes/activity/+page.svelte diff --git a/routes/alerts/+page.svelte b/src/routes/alerts/+page.svelte similarity index 100% rename from routes/alerts/+page.svelte rename to src/routes/alerts/+page.svelte diff --git a/routes/api/activity/+server.ts b/src/routes/api/activity/+server.ts similarity index 100% rename from routes/api/activity/+server.ts rename to src/routes/api/activity/+server.ts diff --git a/routes/api/activity/containers/+server.ts b/src/routes/api/activity/containers/+server.ts similarity index 100% rename from routes/api/activity/containers/+server.ts rename to src/routes/api/activity/containers/+server.ts diff --git a/routes/api/activity/events/+server.ts b/src/routes/api/activity/events/+server.ts similarity index 100% rename from routes/api/activity/events/+server.ts rename to src/routes/api/activity/events/+server.ts diff --git a/routes/api/activity/stats/+server.ts b/src/routes/api/activity/stats/+server.ts similarity index 100% rename from routes/api/activity/stats/+server.ts rename to src/routes/api/activity/stats/+server.ts diff --git a/routes/api/audit/+server.ts b/src/routes/api/audit/+server.ts similarity index 100% rename from routes/api/audit/+server.ts rename to src/routes/api/audit/+server.ts diff --git a/routes/api/audit/events/+server.ts b/src/routes/api/audit/events/+server.ts similarity index 100% rename from routes/api/audit/events/+server.ts rename to src/routes/api/audit/events/+server.ts diff --git a/routes/api/audit/export/+server.ts b/src/routes/api/audit/export/+server.ts similarity index 100% rename from routes/api/audit/export/+server.ts rename to src/routes/api/audit/export/+server.ts diff --git a/routes/api/audit/users/+server.ts b/src/routes/api/audit/users/+server.ts similarity index 100% rename from routes/api/audit/users/+server.ts rename to src/routes/api/audit/users/+server.ts diff --git a/routes/api/auth/ldap/+server.ts b/src/routes/api/auth/ldap/+server.ts similarity index 100% rename from routes/api/auth/ldap/+server.ts rename to src/routes/api/auth/ldap/+server.ts diff --git a/routes/api/auth/ldap/[id]/+server.ts b/src/routes/api/auth/ldap/[id]/+server.ts similarity index 100% rename from routes/api/auth/ldap/[id]/+server.ts rename to src/routes/api/auth/ldap/[id]/+server.ts diff --git a/routes/api/auth/ldap/[id]/test/+server.ts b/src/routes/api/auth/ldap/[id]/test/+server.ts similarity index 100% rename from routes/api/auth/ldap/[id]/test/+server.ts rename to src/routes/api/auth/ldap/[id]/test/+server.ts diff --git a/routes/api/auth/login/+server.ts b/src/routes/api/auth/login/+server.ts similarity index 100% rename from routes/api/auth/login/+server.ts rename to src/routes/api/auth/login/+server.ts diff --git a/routes/api/auth/logout/+server.ts b/src/routes/api/auth/logout/+server.ts similarity index 100% rename from routes/api/auth/logout/+server.ts rename to src/routes/api/auth/logout/+server.ts diff --git a/routes/api/auth/oidc/+server.ts b/src/routes/api/auth/oidc/+server.ts similarity index 100% rename from routes/api/auth/oidc/+server.ts rename to src/routes/api/auth/oidc/+server.ts diff --git a/routes/api/auth/oidc/[id]/+server.ts b/src/routes/api/auth/oidc/[id]/+server.ts similarity index 100% rename from routes/api/auth/oidc/[id]/+server.ts rename to src/routes/api/auth/oidc/[id]/+server.ts diff --git a/routes/api/auth/oidc/[id]/initiate/+server.ts b/src/routes/api/auth/oidc/[id]/initiate/+server.ts similarity index 100% rename from routes/api/auth/oidc/[id]/initiate/+server.ts rename to src/routes/api/auth/oidc/[id]/initiate/+server.ts diff --git a/routes/api/auth/oidc/[id]/test/+server.ts b/src/routes/api/auth/oidc/[id]/test/+server.ts similarity index 100% rename from routes/api/auth/oidc/[id]/test/+server.ts rename to src/routes/api/auth/oidc/[id]/test/+server.ts diff --git a/routes/api/auth/oidc/callback/+server.ts b/src/routes/api/auth/oidc/callback/+server.ts similarity index 100% rename from routes/api/auth/oidc/callback/+server.ts rename to src/routes/api/auth/oidc/callback/+server.ts diff --git a/routes/api/auth/providers/+server.ts b/src/routes/api/auth/providers/+server.ts similarity index 100% rename from routes/api/auth/providers/+server.ts rename to src/routes/api/auth/providers/+server.ts diff --git a/routes/api/auth/session/+server.ts b/src/routes/api/auth/session/+server.ts similarity index 100% rename from routes/api/auth/session/+server.ts rename to src/routes/api/auth/session/+server.ts diff --git a/routes/api/auth/settings/+server.ts b/src/routes/api/auth/settings/+server.ts similarity index 100% rename from routes/api/auth/settings/+server.ts rename to src/routes/api/auth/settings/+server.ts diff --git a/routes/api/auto-update/+server.ts b/src/routes/api/auto-update/+server.ts similarity index 100% rename from routes/api/auto-update/+server.ts rename to src/routes/api/auto-update/+server.ts diff --git a/routes/api/auto-update/[containerName]/+server.ts b/src/routes/api/auto-update/[containerName]/+server.ts similarity index 100% rename from routes/api/auto-update/[containerName]/+server.ts rename to src/routes/api/auto-update/[containerName]/+server.ts diff --git a/routes/api/batch/+server.ts b/src/routes/api/batch/+server.ts similarity index 100% rename from routes/api/batch/+server.ts rename to src/routes/api/batch/+server.ts diff --git a/routes/api/changelog/+server.ts b/src/routes/api/changelog/+server.ts similarity index 100% rename from routes/api/changelog/+server.ts rename to src/routes/api/changelog/+server.ts diff --git a/routes/api/config-sets/+server.ts b/src/routes/api/config-sets/+server.ts similarity index 100% rename from routes/api/config-sets/+server.ts rename to src/routes/api/config-sets/+server.ts diff --git a/routes/api/config-sets/[id]/+server.ts b/src/routes/api/config-sets/[id]/+server.ts similarity index 100% rename from routes/api/config-sets/[id]/+server.ts rename to src/routes/api/config-sets/[id]/+server.ts diff --git a/routes/api/containers/+server.ts b/src/routes/api/containers/+server.ts similarity index 100% rename from routes/api/containers/+server.ts rename to src/routes/api/containers/+server.ts diff --git a/routes/api/containers/[id]/+server.ts b/src/routes/api/containers/[id]/+server.ts similarity index 100% rename from routes/api/containers/[id]/+server.ts rename to src/routes/api/containers/[id]/+server.ts diff --git a/routes/api/containers/[id]/exec/+server.ts b/src/routes/api/containers/[id]/exec/+server.ts similarity index 100% rename from routes/api/containers/[id]/exec/+server.ts rename to src/routes/api/containers/[id]/exec/+server.ts diff --git a/routes/api/containers/[id]/files/+server.ts b/src/routes/api/containers/[id]/files/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/+server.ts rename to src/routes/api/containers/[id]/files/+server.ts diff --git a/routes/api/containers/[id]/files/chmod/+server.ts b/src/routes/api/containers/[id]/files/chmod/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/chmod/+server.ts rename to src/routes/api/containers/[id]/files/chmod/+server.ts diff --git a/routes/api/containers/[id]/files/content/+server.ts b/src/routes/api/containers/[id]/files/content/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/content/+server.ts rename to src/routes/api/containers/[id]/files/content/+server.ts diff --git a/routes/api/containers/[id]/files/create/+server.ts b/src/routes/api/containers/[id]/files/create/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/create/+server.ts rename to src/routes/api/containers/[id]/files/create/+server.ts diff --git a/routes/api/containers/[id]/files/delete/+server.ts b/src/routes/api/containers/[id]/files/delete/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/delete/+server.ts rename to src/routes/api/containers/[id]/files/delete/+server.ts diff --git a/routes/api/containers/[id]/files/download/+server.ts b/src/routes/api/containers/[id]/files/download/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/download/+server.ts rename to src/routes/api/containers/[id]/files/download/+server.ts diff --git a/routes/api/containers/[id]/files/rename/+server.ts b/src/routes/api/containers/[id]/files/rename/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/rename/+server.ts rename to src/routes/api/containers/[id]/files/rename/+server.ts diff --git a/routes/api/containers/[id]/files/upload/+server.ts b/src/routes/api/containers/[id]/files/upload/+server.ts similarity index 100% rename from routes/api/containers/[id]/files/upload/+server.ts rename to src/routes/api/containers/[id]/files/upload/+server.ts diff --git a/routes/api/containers/[id]/inspect/+server.ts b/src/routes/api/containers/[id]/inspect/+server.ts similarity index 100% rename from routes/api/containers/[id]/inspect/+server.ts rename to src/routes/api/containers/[id]/inspect/+server.ts diff --git a/routes/api/containers/[id]/logs/+server.ts b/src/routes/api/containers/[id]/logs/+server.ts similarity index 100% rename from routes/api/containers/[id]/logs/+server.ts rename to src/routes/api/containers/[id]/logs/+server.ts diff --git a/routes/api/containers/[id]/logs/stream/+server.ts b/src/routes/api/containers/[id]/logs/stream/+server.ts similarity index 100% rename from routes/api/containers/[id]/logs/stream/+server.ts rename to src/routes/api/containers/[id]/logs/stream/+server.ts diff --git a/routes/api/containers/[id]/pause/+server.ts b/src/routes/api/containers/[id]/pause/+server.ts similarity index 100% rename from routes/api/containers/[id]/pause/+server.ts rename to src/routes/api/containers/[id]/pause/+server.ts diff --git a/routes/api/containers/[id]/rename/+server.ts b/src/routes/api/containers/[id]/rename/+server.ts similarity index 100% rename from routes/api/containers/[id]/rename/+server.ts rename to src/routes/api/containers/[id]/rename/+server.ts diff --git a/routes/api/containers/[id]/restart/+server.ts b/src/routes/api/containers/[id]/restart/+server.ts similarity index 100% rename from routes/api/containers/[id]/restart/+server.ts rename to src/routes/api/containers/[id]/restart/+server.ts diff --git a/routes/api/containers/[id]/start/+server.ts b/src/routes/api/containers/[id]/start/+server.ts similarity index 100% rename from routes/api/containers/[id]/start/+server.ts rename to src/routes/api/containers/[id]/start/+server.ts diff --git a/routes/api/containers/[id]/stats/+server.ts b/src/routes/api/containers/[id]/stats/+server.ts similarity index 100% rename from routes/api/containers/[id]/stats/+server.ts rename to src/routes/api/containers/[id]/stats/+server.ts diff --git a/routes/api/containers/[id]/stop/+server.ts b/src/routes/api/containers/[id]/stop/+server.ts similarity index 100% rename from routes/api/containers/[id]/stop/+server.ts rename to src/routes/api/containers/[id]/stop/+server.ts diff --git a/routes/api/containers/[id]/top/+server.ts b/src/routes/api/containers/[id]/top/+server.ts similarity index 100% rename from routes/api/containers/[id]/top/+server.ts rename to src/routes/api/containers/[id]/top/+server.ts diff --git a/routes/api/containers/[id]/unpause/+server.ts b/src/routes/api/containers/[id]/unpause/+server.ts similarity index 100% rename from routes/api/containers/[id]/unpause/+server.ts rename to src/routes/api/containers/[id]/unpause/+server.ts diff --git a/routes/api/containers/[id]/update/+server.ts b/src/routes/api/containers/[id]/update/+server.ts similarity index 100% rename from routes/api/containers/[id]/update/+server.ts rename to src/routes/api/containers/[id]/update/+server.ts diff --git a/routes/api/containers/batch-update-stream/+server.ts b/src/routes/api/containers/batch-update-stream/+server.ts similarity index 100% rename from routes/api/containers/batch-update-stream/+server.ts rename to src/routes/api/containers/batch-update-stream/+server.ts diff --git a/routes/api/containers/batch-update/+server.ts b/src/routes/api/containers/batch-update/+server.ts similarity index 100% rename from routes/api/containers/batch-update/+server.ts rename to src/routes/api/containers/batch-update/+server.ts diff --git a/routes/api/containers/check-updates/+server.ts b/src/routes/api/containers/check-updates/+server.ts similarity index 100% rename from routes/api/containers/check-updates/+server.ts rename to src/routes/api/containers/check-updates/+server.ts diff --git a/routes/api/containers/pending-updates/+server.ts b/src/routes/api/containers/pending-updates/+server.ts similarity index 100% rename from routes/api/containers/pending-updates/+server.ts rename to src/routes/api/containers/pending-updates/+server.ts diff --git a/routes/api/containers/sizes/+server.ts b/src/routes/api/containers/sizes/+server.ts similarity index 100% rename from routes/api/containers/sizes/+server.ts rename to src/routes/api/containers/sizes/+server.ts diff --git a/routes/api/containers/stats/+server.ts b/src/routes/api/containers/stats/+server.ts similarity index 100% rename from routes/api/containers/stats/+server.ts rename to src/routes/api/containers/stats/+server.ts diff --git a/routes/api/dashboard/preferences/+server.ts b/src/routes/api/dashboard/preferences/+server.ts similarity index 100% rename from routes/api/dashboard/preferences/+server.ts rename to src/routes/api/dashboard/preferences/+server.ts diff --git a/routes/api/dashboard/stats/+server.ts b/src/routes/api/dashboard/stats/+server.ts similarity index 100% rename from routes/api/dashboard/stats/+server.ts rename to src/routes/api/dashboard/stats/+server.ts diff --git a/routes/api/dashboard/stats/stream/+server.ts b/src/routes/api/dashboard/stats/stream/+server.ts similarity index 100% rename from routes/api/dashboard/stats/stream/+server.ts rename to src/routes/api/dashboard/stats/stream/+server.ts diff --git a/routes/api/dependencies/+server.ts b/src/routes/api/dependencies/+server.ts similarity index 100% rename from routes/api/dependencies/+server.ts rename to src/routes/api/dependencies/+server.ts diff --git a/routes/api/environments/+server.ts b/src/routes/api/environments/+server.ts similarity index 100% rename from routes/api/environments/+server.ts rename to src/routes/api/environments/+server.ts diff --git a/routes/api/environments/[id]/+server.ts b/src/routes/api/environments/[id]/+server.ts similarity index 100% rename from routes/api/environments/[id]/+server.ts rename to src/routes/api/environments/[id]/+server.ts diff --git a/routes/api/environments/[id]/notifications/+server.ts b/src/routes/api/environments/[id]/notifications/+server.ts similarity index 100% rename from routes/api/environments/[id]/notifications/+server.ts rename to src/routes/api/environments/[id]/notifications/+server.ts diff --git a/routes/api/environments/[id]/notifications/[notificationId]/+server.ts b/src/routes/api/environments/[id]/notifications/[notificationId]/+server.ts similarity index 100% rename from routes/api/environments/[id]/notifications/[notificationId]/+server.ts rename to src/routes/api/environments/[id]/notifications/[notificationId]/+server.ts diff --git a/routes/api/environments/[id]/test/+server.ts b/src/routes/api/environments/[id]/test/+server.ts similarity index 100% rename from routes/api/environments/[id]/test/+server.ts rename to src/routes/api/environments/[id]/test/+server.ts diff --git a/routes/api/environments/[id]/timezone/+server.ts b/src/routes/api/environments/[id]/timezone/+server.ts similarity index 100% rename from routes/api/environments/[id]/timezone/+server.ts rename to src/routes/api/environments/[id]/timezone/+server.ts diff --git a/routes/api/environments/[id]/update-check/+server.ts b/src/routes/api/environments/[id]/update-check/+server.ts similarity index 100% rename from routes/api/environments/[id]/update-check/+server.ts rename to src/routes/api/environments/[id]/update-check/+server.ts diff --git a/routes/api/environments/detect-socket/+server.ts b/src/routes/api/environments/detect-socket/+server.ts similarity index 100% rename from routes/api/environments/detect-socket/+server.ts rename to src/routes/api/environments/detect-socket/+server.ts diff --git a/routes/api/environments/test/+server.ts b/src/routes/api/environments/test/+server.ts similarity index 100% rename from routes/api/environments/test/+server.ts rename to src/routes/api/environments/test/+server.ts diff --git a/routes/api/events/+server.ts b/src/routes/api/events/+server.ts similarity index 100% rename from routes/api/events/+server.ts rename to src/routes/api/events/+server.ts diff --git a/routes/api/git/credentials/+server.ts b/src/routes/api/git/credentials/+server.ts similarity index 100% rename from routes/api/git/credentials/+server.ts rename to src/routes/api/git/credentials/+server.ts diff --git a/routes/api/git/credentials/[id]/+server.ts b/src/routes/api/git/credentials/[id]/+server.ts similarity index 100% rename from routes/api/git/credentials/[id]/+server.ts rename to src/routes/api/git/credentials/[id]/+server.ts diff --git a/routes/api/git/repositories/+server.ts b/src/routes/api/git/repositories/+server.ts similarity index 100% rename from routes/api/git/repositories/+server.ts rename to src/routes/api/git/repositories/+server.ts diff --git a/routes/api/git/repositories/[id]/+server.ts b/src/routes/api/git/repositories/[id]/+server.ts similarity index 100% rename from routes/api/git/repositories/[id]/+server.ts rename to src/routes/api/git/repositories/[id]/+server.ts diff --git a/routes/api/git/repositories/[id]/deploy/+server.ts b/src/routes/api/git/repositories/[id]/deploy/+server.ts similarity index 100% rename from routes/api/git/repositories/[id]/deploy/+server.ts rename to src/routes/api/git/repositories/[id]/deploy/+server.ts diff --git a/routes/api/git/repositories/[id]/sync/+server.ts b/src/routes/api/git/repositories/[id]/sync/+server.ts similarity index 100% rename from routes/api/git/repositories/[id]/sync/+server.ts rename to src/routes/api/git/repositories/[id]/sync/+server.ts diff --git a/routes/api/git/repositories/[id]/test/+server.ts b/src/routes/api/git/repositories/[id]/test/+server.ts similarity index 100% rename from routes/api/git/repositories/[id]/test/+server.ts rename to src/routes/api/git/repositories/[id]/test/+server.ts diff --git a/routes/api/git/repositories/test/+server.ts b/src/routes/api/git/repositories/test/+server.ts similarity index 100% rename from routes/api/git/repositories/test/+server.ts rename to src/routes/api/git/repositories/test/+server.ts diff --git a/routes/api/git/stacks/+server.ts b/src/routes/api/git/stacks/+server.ts similarity index 100% rename from routes/api/git/stacks/+server.ts rename to src/routes/api/git/stacks/+server.ts diff --git a/routes/api/git/stacks/[id]/+server.ts b/src/routes/api/git/stacks/[id]/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/+server.ts rename to src/routes/api/git/stacks/[id]/+server.ts diff --git a/routes/api/git/stacks/[id]/deploy-stream/+server.ts b/src/routes/api/git/stacks/[id]/deploy-stream/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/deploy-stream/+server.ts rename to src/routes/api/git/stacks/[id]/deploy-stream/+server.ts diff --git a/routes/api/git/stacks/[id]/deploy/+server.ts b/src/routes/api/git/stacks/[id]/deploy/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/deploy/+server.ts rename to src/routes/api/git/stacks/[id]/deploy/+server.ts diff --git a/routes/api/git/stacks/[id]/env-files/+server.ts b/src/routes/api/git/stacks/[id]/env-files/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/env-files/+server.ts rename to src/routes/api/git/stacks/[id]/env-files/+server.ts diff --git a/routes/api/git/stacks/[id]/sync/+server.ts b/src/routes/api/git/stacks/[id]/sync/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/sync/+server.ts rename to src/routes/api/git/stacks/[id]/sync/+server.ts diff --git a/routes/api/git/stacks/[id]/test/+server.ts b/src/routes/api/git/stacks/[id]/test/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/test/+server.ts rename to src/routes/api/git/stacks/[id]/test/+server.ts diff --git a/routes/api/git/stacks/[id]/webhook/+server.ts b/src/routes/api/git/stacks/[id]/webhook/+server.ts similarity index 100% rename from routes/api/git/stacks/[id]/webhook/+server.ts rename to src/routes/api/git/stacks/[id]/webhook/+server.ts diff --git a/routes/api/git/webhook/[id]/+server.ts b/src/routes/api/git/webhook/[id]/+server.ts similarity index 100% rename from routes/api/git/webhook/[id]/+server.ts rename to src/routes/api/git/webhook/[id]/+server.ts diff --git a/routes/api/hawser/connect/+server.ts b/src/routes/api/hawser/connect/+server.ts similarity index 100% rename from routes/api/hawser/connect/+server.ts rename to src/routes/api/hawser/connect/+server.ts diff --git a/routes/api/hawser/tokens/+server.ts b/src/routes/api/hawser/tokens/+server.ts similarity index 100% rename from routes/api/hawser/tokens/+server.ts rename to src/routes/api/hawser/tokens/+server.ts diff --git a/routes/api/health/+server.ts b/src/routes/api/health/+server.ts similarity index 100% rename from routes/api/health/+server.ts rename to src/routes/api/health/+server.ts diff --git a/routes/api/health/database/+server.ts b/src/routes/api/health/database/+server.ts similarity index 100% rename from routes/api/health/database/+server.ts rename to src/routes/api/health/database/+server.ts diff --git a/routes/api/host/+server.ts b/src/routes/api/host/+server.ts similarity index 100% rename from routes/api/host/+server.ts rename to src/routes/api/host/+server.ts diff --git a/routes/api/images/+server.ts b/src/routes/api/images/+server.ts similarity index 100% rename from routes/api/images/+server.ts rename to src/routes/api/images/+server.ts diff --git a/routes/api/images/[id]/+server.ts b/src/routes/api/images/[id]/+server.ts similarity index 100% rename from routes/api/images/[id]/+server.ts rename to src/routes/api/images/[id]/+server.ts diff --git a/routes/api/images/[id]/export/+server.ts b/src/routes/api/images/[id]/export/+server.ts similarity index 100% rename from routes/api/images/[id]/export/+server.ts rename to src/routes/api/images/[id]/export/+server.ts diff --git a/routes/api/images/[id]/history/+server.ts b/src/routes/api/images/[id]/history/+server.ts similarity index 100% rename from routes/api/images/[id]/history/+server.ts rename to src/routes/api/images/[id]/history/+server.ts diff --git a/routes/api/images/[id]/tag/+server.ts b/src/routes/api/images/[id]/tag/+server.ts similarity index 100% rename from routes/api/images/[id]/tag/+server.ts rename to src/routes/api/images/[id]/tag/+server.ts diff --git a/routes/api/images/pull/+server.ts b/src/routes/api/images/pull/+server.ts similarity index 100% rename from routes/api/images/pull/+server.ts rename to src/routes/api/images/pull/+server.ts diff --git a/routes/api/images/push/+server.ts b/src/routes/api/images/push/+server.ts similarity index 100% rename from routes/api/images/push/+server.ts rename to src/routes/api/images/push/+server.ts diff --git a/routes/api/images/scan/+server.ts b/src/routes/api/images/scan/+server.ts similarity index 100% rename from routes/api/images/scan/+server.ts rename to src/routes/api/images/scan/+server.ts diff --git a/routes/api/legal/license/+server.ts b/src/routes/api/legal/license/+server.ts similarity index 100% rename from routes/api/legal/license/+server.ts rename to src/routes/api/legal/license/+server.ts diff --git a/routes/api/legal/privacy/+server.ts b/src/routes/api/legal/privacy/+server.ts similarity index 100% rename from routes/api/legal/privacy/+server.ts rename to src/routes/api/legal/privacy/+server.ts diff --git a/routes/api/license/+server.ts b/src/routes/api/license/+server.ts similarity index 100% rename from routes/api/license/+server.ts rename to src/routes/api/license/+server.ts diff --git a/routes/api/logs/merged/+server.ts b/src/routes/api/logs/merged/+server.ts similarity index 100% rename from routes/api/logs/merged/+server.ts rename to src/routes/api/logs/merged/+server.ts diff --git a/routes/api/metrics/+server.ts b/src/routes/api/metrics/+server.ts similarity index 100% rename from routes/api/metrics/+server.ts rename to src/routes/api/metrics/+server.ts diff --git a/routes/api/networks/+server.ts b/src/routes/api/networks/+server.ts similarity index 100% rename from routes/api/networks/+server.ts rename to src/routes/api/networks/+server.ts diff --git a/routes/api/networks/[id]/+server.ts b/src/routes/api/networks/[id]/+server.ts similarity index 100% rename from routes/api/networks/[id]/+server.ts rename to src/routes/api/networks/[id]/+server.ts diff --git a/routes/api/networks/[id]/connect/+server.ts b/src/routes/api/networks/[id]/connect/+server.ts similarity index 100% rename from routes/api/networks/[id]/connect/+server.ts rename to src/routes/api/networks/[id]/connect/+server.ts diff --git a/routes/api/networks/[id]/disconnect/+server.ts b/src/routes/api/networks/[id]/disconnect/+server.ts similarity index 100% rename from routes/api/networks/[id]/disconnect/+server.ts rename to src/routes/api/networks/[id]/disconnect/+server.ts diff --git a/routes/api/networks/[id]/inspect/+server.ts b/src/routes/api/networks/[id]/inspect/+server.ts similarity index 100% rename from routes/api/networks/[id]/inspect/+server.ts rename to src/routes/api/networks/[id]/inspect/+server.ts diff --git a/routes/api/notifications/+server.ts b/src/routes/api/notifications/+server.ts similarity index 100% rename from routes/api/notifications/+server.ts rename to src/routes/api/notifications/+server.ts diff --git a/routes/api/notifications/[id]/+server.ts b/src/routes/api/notifications/[id]/+server.ts similarity index 100% rename from routes/api/notifications/[id]/+server.ts rename to src/routes/api/notifications/[id]/+server.ts diff --git a/routes/api/notifications/[id]/test/+server.ts b/src/routes/api/notifications/[id]/test/+server.ts similarity index 100% rename from routes/api/notifications/[id]/test/+server.ts rename to src/routes/api/notifications/[id]/test/+server.ts diff --git a/routes/api/notifications/test/+server.ts b/src/routes/api/notifications/test/+server.ts similarity index 100% rename from routes/api/notifications/test/+server.ts rename to src/routes/api/notifications/test/+server.ts diff --git a/routes/api/notifications/trigger-test/+server.ts b/src/routes/api/notifications/trigger-test/+server.ts similarity index 100% rename from routes/api/notifications/trigger-test/+server.ts rename to src/routes/api/notifications/trigger-test/+server.ts diff --git a/routes/api/preferences/favorite-groups/+server.ts b/src/routes/api/preferences/favorite-groups/+server.ts similarity index 100% rename from routes/api/preferences/favorite-groups/+server.ts rename to src/routes/api/preferences/favorite-groups/+server.ts diff --git a/routes/api/preferences/favorites/+server.ts b/src/routes/api/preferences/favorites/+server.ts similarity index 100% rename from routes/api/preferences/favorites/+server.ts rename to src/routes/api/preferences/favorites/+server.ts diff --git a/routes/api/preferences/grid/+server.ts b/src/routes/api/preferences/grid/+server.ts similarity index 100% rename from routes/api/preferences/grid/+server.ts rename to src/routes/api/preferences/grid/+server.ts diff --git a/routes/api/profile/+server.ts b/src/routes/api/profile/+server.ts similarity index 100% rename from routes/api/profile/+server.ts rename to src/routes/api/profile/+server.ts diff --git a/routes/api/profile/avatar/+server.ts b/src/routes/api/profile/avatar/+server.ts similarity index 100% rename from routes/api/profile/avatar/+server.ts rename to src/routes/api/profile/avatar/+server.ts diff --git a/routes/api/profile/preferences/+server.ts b/src/routes/api/profile/preferences/+server.ts similarity index 100% rename from routes/api/profile/preferences/+server.ts rename to src/routes/api/profile/preferences/+server.ts diff --git a/routes/api/prune/all/+server.ts b/src/routes/api/prune/all/+server.ts similarity index 100% rename from routes/api/prune/all/+server.ts rename to src/routes/api/prune/all/+server.ts diff --git a/routes/api/prune/containers/+server.ts b/src/routes/api/prune/containers/+server.ts similarity index 100% rename from routes/api/prune/containers/+server.ts rename to src/routes/api/prune/containers/+server.ts diff --git a/routes/api/prune/images/+server.ts b/src/routes/api/prune/images/+server.ts similarity index 100% rename from routes/api/prune/images/+server.ts rename to src/routes/api/prune/images/+server.ts diff --git a/routes/api/prune/networks/+server.ts b/src/routes/api/prune/networks/+server.ts similarity index 100% rename from routes/api/prune/networks/+server.ts rename to src/routes/api/prune/networks/+server.ts diff --git a/routes/api/prune/volumes/+server.ts b/src/routes/api/prune/volumes/+server.ts similarity index 100% rename from routes/api/prune/volumes/+server.ts rename to src/routes/api/prune/volumes/+server.ts diff --git a/routes/api/registries/+server.ts b/src/routes/api/registries/+server.ts similarity index 100% rename from routes/api/registries/+server.ts rename to src/routes/api/registries/+server.ts diff --git a/routes/api/registries/[id]/+server.ts b/src/routes/api/registries/[id]/+server.ts similarity index 100% rename from routes/api/registries/[id]/+server.ts rename to src/routes/api/registries/[id]/+server.ts diff --git a/routes/api/registries/[id]/default/+server.ts b/src/routes/api/registries/[id]/default/+server.ts similarity index 100% rename from routes/api/registries/[id]/default/+server.ts rename to src/routes/api/registries/[id]/default/+server.ts diff --git a/routes/api/registry/catalog/+server.ts b/src/routes/api/registry/catalog/+server.ts similarity index 100% rename from routes/api/registry/catalog/+server.ts rename to src/routes/api/registry/catalog/+server.ts diff --git a/routes/api/registry/image/+server.ts b/src/routes/api/registry/image/+server.ts similarity index 100% rename from routes/api/registry/image/+server.ts rename to src/routes/api/registry/image/+server.ts diff --git a/routes/api/registry/search/+server.ts b/src/routes/api/registry/search/+server.ts similarity index 100% rename from routes/api/registry/search/+server.ts rename to src/routes/api/registry/search/+server.ts diff --git a/routes/api/registry/tags/+server.ts b/src/routes/api/registry/tags/+server.ts similarity index 100% rename from routes/api/registry/tags/+server.ts rename to src/routes/api/registry/tags/+server.ts diff --git a/routes/api/roles/+server.ts b/src/routes/api/roles/+server.ts similarity index 100% rename from routes/api/roles/+server.ts rename to src/routes/api/roles/+server.ts diff --git a/routes/api/roles/[id]/+server.ts b/src/routes/api/roles/[id]/+server.ts similarity index 100% rename from routes/api/roles/[id]/+server.ts rename to src/routes/api/roles/[id]/+server.ts diff --git a/routes/api/schedules/+server.ts b/src/routes/api/schedules/+server.ts similarity index 100% rename from routes/api/schedules/+server.ts rename to src/routes/api/schedules/+server.ts diff --git a/routes/api/schedules/[type]/[id]/+server.ts b/src/routes/api/schedules/[type]/[id]/+server.ts similarity index 100% rename from routes/api/schedules/[type]/[id]/+server.ts rename to src/routes/api/schedules/[type]/[id]/+server.ts diff --git a/routes/api/schedules/[type]/[id]/run/+server.ts b/src/routes/api/schedules/[type]/[id]/run/+server.ts similarity index 100% rename from routes/api/schedules/[type]/[id]/run/+server.ts rename to src/routes/api/schedules/[type]/[id]/run/+server.ts diff --git a/routes/api/schedules/[type]/[id]/toggle/+server.ts b/src/routes/api/schedules/[type]/[id]/toggle/+server.ts similarity index 100% rename from routes/api/schedules/[type]/[id]/toggle/+server.ts rename to src/routes/api/schedules/[type]/[id]/toggle/+server.ts diff --git a/routes/api/schedules/executions/+server.ts b/src/routes/api/schedules/executions/+server.ts similarity index 100% rename from routes/api/schedules/executions/+server.ts rename to src/routes/api/schedules/executions/+server.ts diff --git a/routes/api/schedules/executions/[id]/+server.ts b/src/routes/api/schedules/executions/[id]/+server.ts similarity index 100% rename from routes/api/schedules/executions/[id]/+server.ts rename to src/routes/api/schedules/executions/[id]/+server.ts diff --git a/routes/api/schedules/settings/+server.ts b/src/routes/api/schedules/settings/+server.ts similarity index 100% rename from routes/api/schedules/settings/+server.ts rename to src/routes/api/schedules/settings/+server.ts diff --git a/routes/api/schedules/stream/+server.ts b/src/routes/api/schedules/stream/+server.ts similarity index 100% rename from routes/api/schedules/stream/+server.ts rename to src/routes/api/schedules/stream/+server.ts diff --git a/routes/api/schedules/system/[id]/toggle/+server.ts b/src/routes/api/schedules/system/[id]/toggle/+server.ts similarity index 100% rename from routes/api/schedules/system/[id]/toggle/+server.ts rename to src/routes/api/schedules/system/[id]/toggle/+server.ts diff --git a/routes/api/settings/general/+server.ts b/src/routes/api/settings/general/+server.ts similarity index 100% rename from routes/api/settings/general/+server.ts rename to src/routes/api/settings/general/+server.ts diff --git a/routes/api/settings/scanner/+server.ts b/src/routes/api/settings/scanner/+server.ts similarity index 100% rename from routes/api/settings/scanner/+server.ts rename to src/routes/api/settings/scanner/+server.ts diff --git a/routes/api/stacks/+server.ts b/src/routes/api/stacks/+server.ts similarity index 100% rename from routes/api/stacks/+server.ts rename to src/routes/api/stacks/+server.ts diff --git a/routes/api/stacks/[name]/+server.ts b/src/routes/api/stacks/[name]/+server.ts similarity index 100% rename from routes/api/stacks/[name]/+server.ts rename to src/routes/api/stacks/[name]/+server.ts diff --git a/routes/api/stacks/[name]/compose/+server.ts b/src/routes/api/stacks/[name]/compose/+server.ts similarity index 100% rename from routes/api/stacks/[name]/compose/+server.ts rename to src/routes/api/stacks/[name]/compose/+server.ts diff --git a/routes/api/stacks/[name]/down/+server.ts b/src/routes/api/stacks/[name]/down/+server.ts similarity index 100% rename from routes/api/stacks/[name]/down/+server.ts rename to src/routes/api/stacks/[name]/down/+server.ts diff --git a/routes/api/stacks/[name]/env/+server.ts b/src/routes/api/stacks/[name]/env/+server.ts similarity index 100% rename from routes/api/stacks/[name]/env/+server.ts rename to src/routes/api/stacks/[name]/env/+server.ts diff --git a/routes/api/stacks/[name]/env/validate/+server.ts b/src/routes/api/stacks/[name]/env/validate/+server.ts similarity index 100% rename from routes/api/stacks/[name]/env/validate/+server.ts rename to src/routes/api/stacks/[name]/env/validate/+server.ts diff --git a/routes/api/stacks/[name]/restart/+server.ts b/src/routes/api/stacks/[name]/restart/+server.ts similarity index 100% rename from routes/api/stacks/[name]/restart/+server.ts rename to src/routes/api/stacks/[name]/restart/+server.ts diff --git a/routes/api/stacks/[name]/start/+server.ts b/src/routes/api/stacks/[name]/start/+server.ts similarity index 100% rename from routes/api/stacks/[name]/start/+server.ts rename to src/routes/api/stacks/[name]/start/+server.ts diff --git a/routes/api/stacks/[name]/stop/+server.ts b/src/routes/api/stacks/[name]/stop/+server.ts similarity index 100% rename from routes/api/stacks/[name]/stop/+server.ts rename to src/routes/api/stacks/[name]/stop/+server.ts diff --git a/routes/api/stacks/sources/+server.ts b/src/routes/api/stacks/sources/+server.ts similarity index 100% rename from routes/api/stacks/sources/+server.ts rename to src/routes/api/stacks/sources/+server.ts diff --git a/routes/api/system/+server.ts b/src/routes/api/system/+server.ts similarity index 100% rename from routes/api/system/+server.ts rename to src/routes/api/system/+server.ts diff --git a/routes/api/system/disk/+server.ts b/src/routes/api/system/disk/+server.ts similarity index 100% rename from routes/api/system/disk/+server.ts rename to src/routes/api/system/disk/+server.ts diff --git a/routes/api/users/+server.ts b/src/routes/api/users/+server.ts similarity index 100% rename from routes/api/users/+server.ts rename to src/routes/api/users/+server.ts diff --git a/routes/api/users/[id]/+server.ts b/src/routes/api/users/[id]/+server.ts similarity index 100% rename from routes/api/users/[id]/+server.ts rename to src/routes/api/users/[id]/+server.ts diff --git a/routes/api/users/[id]/mfa/+server.ts b/src/routes/api/users/[id]/mfa/+server.ts similarity index 100% rename from routes/api/users/[id]/mfa/+server.ts rename to src/routes/api/users/[id]/mfa/+server.ts diff --git a/routes/api/users/[id]/roles/+server.ts b/src/routes/api/users/[id]/roles/+server.ts similarity index 100% rename from routes/api/users/[id]/roles/+server.ts rename to src/routes/api/users/[id]/roles/+server.ts diff --git a/routes/api/volumes/+server.ts b/src/routes/api/volumes/+server.ts similarity index 100% rename from routes/api/volumes/+server.ts rename to src/routes/api/volumes/+server.ts diff --git a/routes/api/volumes/[name]/+server.ts b/src/routes/api/volumes/[name]/+server.ts similarity index 100% rename from routes/api/volumes/[name]/+server.ts rename to src/routes/api/volumes/[name]/+server.ts diff --git a/routes/api/volumes/[name]/browse/+server.ts b/src/routes/api/volumes/[name]/browse/+server.ts similarity index 100% rename from routes/api/volumes/[name]/browse/+server.ts rename to src/routes/api/volumes/[name]/browse/+server.ts diff --git a/routes/api/volumes/[name]/browse/content/+server.ts b/src/routes/api/volumes/[name]/browse/content/+server.ts similarity index 100% rename from routes/api/volumes/[name]/browse/content/+server.ts rename to src/routes/api/volumes/[name]/browse/content/+server.ts diff --git a/routes/api/volumes/[name]/browse/release/+server.ts b/src/routes/api/volumes/[name]/browse/release/+server.ts similarity index 100% rename from routes/api/volumes/[name]/browse/release/+server.ts rename to src/routes/api/volumes/[name]/browse/release/+server.ts diff --git a/routes/api/volumes/[name]/clone/+server.ts b/src/routes/api/volumes/[name]/clone/+server.ts similarity index 100% rename from routes/api/volumes/[name]/clone/+server.ts rename to src/routes/api/volumes/[name]/clone/+server.ts diff --git a/routes/api/volumes/[name]/export/+server.ts b/src/routes/api/volumes/[name]/export/+server.ts similarity index 100% rename from routes/api/volumes/[name]/export/+server.ts rename to src/routes/api/volumes/[name]/export/+server.ts diff --git a/routes/api/volumes/[name]/inspect/+server.ts b/src/routes/api/volumes/[name]/inspect/+server.ts similarity index 100% rename from routes/api/volumes/[name]/inspect/+server.ts rename to src/routes/api/volumes/[name]/inspect/+server.ts diff --git a/routes/audit/+page.svelte b/src/routes/audit/+page.svelte similarity index 100% rename from routes/audit/+page.svelte rename to src/routes/audit/+page.svelte diff --git a/routes/audit/+server.ts b/src/routes/audit/+server.ts similarity index 100% rename from routes/audit/+server.ts rename to src/routes/audit/+server.ts diff --git a/routes/audit/users/+server.ts b/src/routes/audit/users/+server.ts similarity index 100% rename from routes/audit/users/+server.ts rename to src/routes/audit/users/+server.ts diff --git a/routes/containers/+page.svelte b/src/routes/containers/+page.svelte similarity index 100% rename from routes/containers/+page.svelte rename to src/routes/containers/+page.svelte diff --git a/routes/containers/AutoUpdateSettings.svelte b/src/routes/containers/AutoUpdateSettings.svelte similarity index 100% rename from routes/containers/AutoUpdateSettings.svelte rename to src/routes/containers/AutoUpdateSettings.svelte diff --git a/routes/containers/BatchUpdateModal.svelte b/src/routes/containers/BatchUpdateModal.svelte similarity index 100% rename from routes/containers/BatchUpdateModal.svelte rename to src/routes/containers/BatchUpdateModal.svelte diff --git a/routes/containers/ContainerInspectModal.svelte b/src/routes/containers/ContainerInspectModal.svelte similarity index 100% rename from routes/containers/ContainerInspectModal.svelte rename to src/routes/containers/ContainerInspectModal.svelte diff --git a/routes/containers/ContainerTerminal.svelte b/src/routes/containers/ContainerTerminal.svelte similarity index 100% rename from routes/containers/ContainerTerminal.svelte rename to src/routes/containers/ContainerTerminal.svelte diff --git a/routes/containers/ContainerTile.svelte b/src/routes/containers/ContainerTile.svelte similarity index 100% rename from routes/containers/ContainerTile.svelte rename to src/routes/containers/ContainerTile.svelte diff --git a/routes/containers/CreateContainerModal.svelte b/src/routes/containers/CreateContainerModal.svelte similarity index 100% rename from routes/containers/CreateContainerModal.svelte rename to src/routes/containers/CreateContainerModal.svelte diff --git a/routes/containers/EditContainerModal.svelte b/src/routes/containers/EditContainerModal.svelte similarity index 100% rename from routes/containers/EditContainerModal.svelte rename to src/routes/containers/EditContainerModal.svelte diff --git a/routes/containers/FileBrowserModal.svelte b/src/routes/containers/FileBrowserModal.svelte similarity index 100% rename from routes/containers/FileBrowserModal.svelte rename to src/routes/containers/FileBrowserModal.svelte diff --git a/routes/containers/FileBrowserPanel.svelte b/src/routes/containers/FileBrowserPanel.svelte similarity index 100% rename from routes/containers/FileBrowserPanel.svelte rename to src/routes/containers/FileBrowserPanel.svelte diff --git a/routes/dashboard/DraggableGrid.svelte b/src/routes/dashboard/DraggableGrid.svelte similarity index 100% rename from routes/dashboard/DraggableGrid.svelte rename to src/routes/dashboard/DraggableGrid.svelte diff --git a/routes/dashboard/EnvironmentTile.svelte b/src/routes/dashboard/EnvironmentTile.svelte similarity index 100% rename from routes/dashboard/EnvironmentTile.svelte rename to src/routes/dashboard/EnvironmentTile.svelte diff --git a/routes/dashboard/EnvironmentTileSkeleton.svelte b/src/routes/dashboard/EnvironmentTileSkeleton.svelte similarity index 100% rename from routes/dashboard/EnvironmentTileSkeleton.svelte rename to src/routes/dashboard/EnvironmentTileSkeleton.svelte diff --git a/routes/dashboard/dashboard-container-stats.svelte b/src/routes/dashboard/dashboard-container-stats.svelte similarity index 100% rename from routes/dashboard/dashboard-container-stats.svelte rename to src/routes/dashboard/dashboard-container-stats.svelte diff --git a/routes/dashboard/dashboard-cpu-memory-bars.svelte b/src/routes/dashboard/dashboard-cpu-memory-bars.svelte similarity index 100% rename from routes/dashboard/dashboard-cpu-memory-bars.svelte rename to src/routes/dashboard/dashboard-cpu-memory-bars.svelte diff --git a/routes/dashboard/dashboard-cpu-memory-charts.svelte b/src/routes/dashboard/dashboard-cpu-memory-charts.svelte similarity index 100% rename from routes/dashboard/dashboard-cpu-memory-charts.svelte rename to src/routes/dashboard/dashboard-cpu-memory-charts.svelte diff --git a/routes/dashboard/dashboard-disk-usage.svelte b/src/routes/dashboard/dashboard-disk-usage.svelte similarity index 100% rename from routes/dashboard/dashboard-disk-usage.svelte rename to src/routes/dashboard/dashboard-disk-usage.svelte diff --git a/routes/dashboard/dashboard-events-summary.svelte b/src/routes/dashboard/dashboard-events-summary.svelte similarity index 100% rename from routes/dashboard/dashboard-events-summary.svelte rename to src/routes/dashboard/dashboard-events-summary.svelte diff --git a/routes/dashboard/dashboard-header.svelte b/src/routes/dashboard/dashboard-header.svelte similarity index 100% rename from routes/dashboard/dashboard-header.svelte rename to src/routes/dashboard/dashboard-header.svelte diff --git a/routes/dashboard/dashboard-health-banner.svelte b/src/routes/dashboard/dashboard-health-banner.svelte similarity index 100% rename from routes/dashboard/dashboard-health-banner.svelte rename to src/routes/dashboard/dashboard-health-banner.svelte diff --git a/routes/dashboard/dashboard-labels.svelte b/src/routes/dashboard/dashboard-labels.svelte similarity index 100% rename from routes/dashboard/dashboard-labels.svelte rename to src/routes/dashboard/dashboard-labels.svelte diff --git a/routes/dashboard/dashboard-offline-state.svelte b/src/routes/dashboard/dashboard-offline-state.svelte similarity index 100% rename from routes/dashboard/dashboard-offline-state.svelte rename to src/routes/dashboard/dashboard-offline-state.svelte diff --git a/routes/dashboard/dashboard-recent-events.svelte b/src/routes/dashboard/dashboard-recent-events.svelte similarity index 100% rename from routes/dashboard/dashboard-recent-events.svelte rename to src/routes/dashboard/dashboard-recent-events.svelte diff --git a/routes/dashboard/dashboard-resource-stats.svelte b/src/routes/dashboard/dashboard-resource-stats.svelte similarity index 100% rename from routes/dashboard/dashboard-resource-stats.svelte rename to src/routes/dashboard/dashboard-resource-stats.svelte diff --git a/routes/dashboard/dashboard-status-icons.svelte b/src/routes/dashboard/dashboard-status-icons.svelte similarity index 100% rename from routes/dashboard/dashboard-status-icons.svelte rename to src/routes/dashboard/dashboard-status-icons.svelte diff --git a/routes/dashboard/dashboard-top-containers.svelte b/src/routes/dashboard/dashboard-top-containers.svelte similarity index 100% rename from routes/dashboard/dashboard-top-containers.svelte rename to src/routes/dashboard/dashboard-top-containers.svelte diff --git a/routes/dashboard/index.ts b/src/routes/dashboard/index.ts similarity index 100% rename from routes/dashboard/index.ts rename to src/routes/dashboard/index.ts diff --git a/routes/environments/+page.svelte b/src/routes/environments/+page.svelte similarity index 100% rename from routes/environments/+page.svelte rename to src/routes/environments/+page.svelte diff --git a/routes/images/+page.server.ts b/src/routes/images/+page.server.ts similarity index 100% rename from routes/images/+page.server.ts rename to src/routes/images/+page.server.ts diff --git a/routes/images/+page.svelte b/src/routes/images/+page.svelte similarity index 100% rename from routes/images/+page.svelte rename to src/routes/images/+page.svelte diff --git a/routes/images/ImageHistoryModal.svelte b/src/routes/images/ImageHistoryModal.svelte similarity index 100% rename from routes/images/ImageHistoryModal.svelte rename to src/routes/images/ImageHistoryModal.svelte diff --git a/routes/images/ImageLayersView.svelte b/src/routes/images/ImageLayersView.svelte similarity index 100% rename from routes/images/ImageLayersView.svelte rename to src/routes/images/ImageLayersView.svelte diff --git a/routes/images/ImagePullProgressPopover.svelte b/src/routes/images/ImagePullProgressPopover.svelte similarity index 100% rename from routes/images/ImagePullProgressPopover.svelte rename to src/routes/images/ImagePullProgressPopover.svelte diff --git a/routes/images/ImageScanModal.svelte b/src/routes/images/ImageScanModal.svelte similarity index 100% rename from routes/images/ImageScanModal.svelte rename to src/routes/images/ImageScanModal.svelte diff --git a/routes/images/PushToRegistryModal.svelte b/src/routes/images/PushToRegistryModal.svelte similarity index 100% rename from routes/images/PushToRegistryModal.svelte rename to src/routes/images/PushToRegistryModal.svelte diff --git a/routes/images/ScanResultsView.svelte b/src/routes/images/ScanResultsView.svelte similarity index 100% rename from routes/images/ScanResultsView.svelte rename to src/routes/images/ScanResultsView.svelte diff --git a/routes/images/VulnerabilityScanModal.svelte b/src/routes/images/VulnerabilityScanModal.svelte similarity index 100% rename from routes/images/VulnerabilityScanModal.svelte rename to src/routes/images/VulnerabilityScanModal.svelte diff --git a/routes/login/+page.svelte b/src/routes/login/+page.svelte similarity index 100% rename from routes/login/+page.svelte rename to src/routes/login/+page.svelte diff --git a/routes/logs/+page.svelte b/src/routes/logs/+page.svelte similarity index 100% rename from routes/logs/+page.svelte rename to src/routes/logs/+page.svelte diff --git a/routes/logs/LogViewer.svelte b/src/routes/logs/LogViewer.svelte similarity index 100% rename from routes/logs/LogViewer.svelte rename to src/routes/logs/LogViewer.svelte diff --git a/routes/logs/LogsPanel.svelte b/src/routes/logs/LogsPanel.svelte similarity index 100% rename from routes/logs/LogsPanel.svelte rename to src/routes/logs/LogsPanel.svelte diff --git a/routes/networks/+page.svelte b/src/routes/networks/+page.svelte similarity index 100% rename from routes/networks/+page.svelte rename to src/routes/networks/+page.svelte diff --git a/routes/networks/ConnectContainerModal.svelte b/src/routes/networks/ConnectContainerModal.svelte similarity index 100% rename from routes/networks/ConnectContainerModal.svelte rename to src/routes/networks/ConnectContainerModal.svelte diff --git a/routes/networks/CreateNetworkModal.svelte b/src/routes/networks/CreateNetworkModal.svelte similarity index 100% rename from routes/networks/CreateNetworkModal.svelte rename to src/routes/networks/CreateNetworkModal.svelte diff --git a/routes/networks/NetworkInspectModal.svelte b/src/routes/networks/NetworkInspectModal.svelte similarity index 100% rename from routes/networks/NetworkInspectModal.svelte rename to src/routes/networks/NetworkInspectModal.svelte diff --git a/routes/profile/+page.svelte b/src/routes/profile/+page.svelte similarity index 100% rename from routes/profile/+page.svelte rename to src/routes/profile/+page.svelte diff --git a/routes/profile/ChangePasswordModal.svelte b/src/routes/profile/ChangePasswordModal.svelte similarity index 100% rename from routes/profile/ChangePasswordModal.svelte rename to src/routes/profile/ChangePasswordModal.svelte diff --git a/routes/profile/DisableMfaModal.svelte b/src/routes/profile/DisableMfaModal.svelte similarity index 100% rename from routes/profile/DisableMfaModal.svelte rename to src/routes/profile/DisableMfaModal.svelte diff --git a/routes/profile/MfaSetupModal.svelte b/src/routes/profile/MfaSetupModal.svelte similarity index 100% rename from routes/profile/MfaSetupModal.svelte rename to src/routes/profile/MfaSetupModal.svelte diff --git a/routes/registry/+page.svelte b/src/routes/registry/+page.svelte similarity index 100% rename from routes/registry/+page.svelte rename to src/routes/registry/+page.svelte diff --git a/routes/registry/CopyToRegistryModal.svelte b/src/routes/registry/CopyToRegistryModal.svelte similarity index 100% rename from routes/registry/CopyToRegistryModal.svelte rename to src/routes/registry/CopyToRegistryModal.svelte diff --git a/routes/registry/ImagePullModal.svelte b/src/routes/registry/ImagePullModal.svelte similarity index 100% rename from routes/registry/ImagePullModal.svelte rename to src/routes/registry/ImagePullModal.svelte diff --git a/routes/schedules/+page.svelte b/src/routes/schedules/+page.svelte similarity index 100% rename from routes/schedules/+page.svelte rename to src/routes/schedules/+page.svelte diff --git a/routes/settings/+page.svelte b/src/routes/settings/+page.svelte similarity index 100% rename from routes/settings/+page.svelte rename to src/routes/settings/+page.svelte diff --git a/routes/settings/about/AboutTab.svelte b/src/routes/settings/about/AboutTab.svelte similarity index 100% rename from routes/settings/about/AboutTab.svelte rename to src/routes/settings/about/AboutTab.svelte diff --git a/routes/settings/about/LicenseModal.svelte b/src/routes/settings/about/LicenseModal.svelte similarity index 100% rename from routes/settings/about/LicenseModal.svelte rename to src/routes/settings/about/LicenseModal.svelte diff --git a/routes/settings/about/PrivacyModal.svelte b/src/routes/settings/about/PrivacyModal.svelte similarity index 100% rename from routes/settings/about/PrivacyModal.svelte rename to src/routes/settings/about/PrivacyModal.svelte diff --git a/routes/settings/auth/AuthTab.svelte b/src/routes/settings/auth/AuthTab.svelte similarity index 100% rename from routes/settings/auth/AuthTab.svelte rename to src/routes/settings/auth/AuthTab.svelte diff --git a/routes/settings/auth/ldap/LdapModal.svelte b/src/routes/settings/auth/ldap/LdapModal.svelte similarity index 100% rename from routes/settings/auth/ldap/LdapModal.svelte rename to src/routes/settings/auth/ldap/LdapModal.svelte diff --git a/routes/settings/auth/ldap/LdapSubTab.svelte b/src/routes/settings/auth/ldap/LdapSubTab.svelte similarity index 100% rename from routes/settings/auth/ldap/LdapSubTab.svelte rename to src/routes/settings/auth/ldap/LdapSubTab.svelte diff --git a/routes/settings/auth/oidc/OidcModal.svelte b/src/routes/settings/auth/oidc/OidcModal.svelte similarity index 100% rename from routes/settings/auth/oidc/OidcModal.svelte rename to src/routes/settings/auth/oidc/OidcModal.svelte diff --git a/routes/settings/auth/oidc/SsoSubTab.svelte b/src/routes/settings/auth/oidc/SsoSubTab.svelte similarity index 100% rename from routes/settings/auth/oidc/SsoSubTab.svelte rename to src/routes/settings/auth/oidc/SsoSubTab.svelte diff --git a/routes/settings/auth/roles/RoleModal.svelte b/src/routes/settings/auth/roles/RoleModal.svelte similarity index 100% rename from routes/settings/auth/roles/RoleModal.svelte rename to src/routes/settings/auth/roles/RoleModal.svelte diff --git a/routes/settings/auth/roles/RolesSubTab.svelte b/src/routes/settings/auth/roles/RolesSubTab.svelte similarity index 100% rename from routes/settings/auth/roles/RolesSubTab.svelte rename to src/routes/settings/auth/roles/RolesSubTab.svelte diff --git a/routes/settings/auth/users/UserModal.svelte b/src/routes/settings/auth/users/UserModal.svelte similarity index 100% rename from routes/settings/auth/users/UserModal.svelte rename to src/routes/settings/auth/users/UserModal.svelte diff --git a/routes/settings/auth/users/UsersSubTab.svelte b/src/routes/settings/auth/users/UsersSubTab.svelte similarity index 100% rename from routes/settings/auth/users/UsersSubTab.svelte rename to src/routes/settings/auth/users/UsersSubTab.svelte diff --git a/routes/settings/config-sets/ConfigSetModal.svelte b/src/routes/settings/config-sets/ConfigSetModal.svelte similarity index 100% rename from routes/settings/config-sets/ConfigSetModal.svelte rename to src/routes/settings/config-sets/ConfigSetModal.svelte diff --git a/routes/settings/config-sets/ConfigSetsTab.svelte b/src/routes/settings/config-sets/ConfigSetsTab.svelte similarity index 100% rename from routes/settings/config-sets/ConfigSetsTab.svelte rename to src/routes/settings/config-sets/ConfigSetsTab.svelte diff --git a/routes/settings/environments/EnvironmentModal.svelte b/src/routes/settings/environments/EnvironmentModal.svelte similarity index 100% rename from routes/settings/environments/EnvironmentModal.svelte rename to src/routes/settings/environments/EnvironmentModal.svelte diff --git a/routes/settings/environments/EnvironmentsTab.svelte b/src/routes/settings/environments/EnvironmentsTab.svelte similarity index 100% rename from routes/settings/environments/EnvironmentsTab.svelte rename to src/routes/settings/environments/EnvironmentsTab.svelte diff --git a/routes/settings/environments/EventTypesEditor.svelte b/src/routes/settings/environments/EventTypesEditor.svelte similarity index 100% rename from routes/settings/environments/EventTypesEditor.svelte rename to src/routes/settings/environments/EventTypesEditor.svelte diff --git a/routes/settings/general/GeneralTab.svelte b/src/routes/settings/general/GeneralTab.svelte similarity index 100% rename from routes/settings/general/GeneralTab.svelte rename to src/routes/settings/general/GeneralTab.svelte diff --git a/routes/settings/git/GitCredentialModal.svelte b/src/routes/settings/git/GitCredentialModal.svelte similarity index 100% rename from routes/settings/git/GitCredentialModal.svelte rename to src/routes/settings/git/GitCredentialModal.svelte diff --git a/routes/settings/git/GitCredentialsTab.svelte b/src/routes/settings/git/GitCredentialsTab.svelte similarity index 100% rename from routes/settings/git/GitCredentialsTab.svelte rename to src/routes/settings/git/GitCredentialsTab.svelte diff --git a/routes/settings/git/GitRepositoriesTab.svelte b/src/routes/settings/git/GitRepositoriesTab.svelte similarity index 100% rename from routes/settings/git/GitRepositoriesTab.svelte rename to src/routes/settings/git/GitRepositoriesTab.svelte diff --git a/routes/settings/git/GitRepositoryModal.svelte b/src/routes/settings/git/GitRepositoryModal.svelte similarity index 100% rename from routes/settings/git/GitRepositoryModal.svelte rename to src/routes/settings/git/GitRepositoryModal.svelte diff --git a/routes/settings/git/GitTab.svelte b/src/routes/settings/git/GitTab.svelte similarity index 100% rename from routes/settings/git/GitTab.svelte rename to src/routes/settings/git/GitTab.svelte diff --git a/routes/settings/license/LicenseTab.svelte b/src/routes/settings/license/LicenseTab.svelte similarity index 100% rename from routes/settings/license/LicenseTab.svelte rename to src/routes/settings/license/LicenseTab.svelte diff --git a/routes/settings/notifications/NotificationModal.svelte b/src/routes/settings/notifications/NotificationModal.svelte similarity index 100% rename from routes/settings/notifications/NotificationModal.svelte rename to src/routes/settings/notifications/NotificationModal.svelte diff --git a/routes/settings/notifications/NotificationsTab.svelte b/src/routes/settings/notifications/NotificationsTab.svelte similarity index 100% rename from routes/settings/notifications/NotificationsTab.svelte rename to src/routes/settings/notifications/NotificationsTab.svelte diff --git a/routes/settings/registries/RegistriesTab.svelte b/src/routes/settings/registries/RegistriesTab.svelte similarity index 100% rename from routes/settings/registries/RegistriesTab.svelte rename to src/routes/settings/registries/RegistriesTab.svelte diff --git a/routes/settings/registries/RegistryModal.svelte b/src/routes/settings/registries/RegistryModal.svelte similarity index 100% rename from routes/settings/registries/RegistryModal.svelte rename to src/routes/settings/registries/RegistryModal.svelte diff --git a/routes/stacks/+page.svelte b/src/routes/stacks/+page.svelte similarity index 100% rename from routes/stacks/+page.svelte rename to src/routes/stacks/+page.svelte diff --git a/routes/stacks/ComposeGraphViewer.svelte b/src/routes/stacks/ComposeGraphViewer.svelte similarity index 100% rename from routes/stacks/ComposeGraphViewer.svelte rename to src/routes/stacks/ComposeGraphViewer.svelte diff --git a/routes/stacks/GitDeployProgressPopover.svelte b/src/routes/stacks/GitDeployProgressPopover.svelte similarity index 100% rename from routes/stacks/GitDeployProgressPopover.svelte rename to src/routes/stacks/GitDeployProgressPopover.svelte diff --git a/routes/stacks/GitStackModal.svelte b/src/routes/stacks/GitStackModal.svelte similarity index 100% rename from routes/stacks/GitStackModal.svelte rename to src/routes/stacks/GitStackModal.svelte diff --git a/routes/stacks/StackModal.svelte b/src/routes/stacks/StackModal.svelte similarity index 100% rename from routes/stacks/StackModal.svelte rename to src/routes/stacks/StackModal.svelte diff --git a/routes/terminal/+page.svelte b/src/routes/terminal/+page.svelte similarity index 100% rename from routes/terminal/+page.svelte rename to src/routes/terminal/+page.svelte diff --git a/routes/terminal/Terminal.svelte b/src/routes/terminal/Terminal.svelte similarity index 100% rename from routes/terminal/Terminal.svelte rename to src/routes/terminal/Terminal.svelte diff --git a/routes/terminal/TerminalEmulator.svelte b/src/routes/terminal/TerminalEmulator.svelte similarity index 100% rename from routes/terminal/TerminalEmulator.svelte rename to src/routes/terminal/TerminalEmulator.svelte diff --git a/routes/terminal/TerminalPanel.svelte b/src/routes/terminal/TerminalPanel.svelte similarity index 100% rename from routes/terminal/TerminalPanel.svelte rename to src/routes/terminal/TerminalPanel.svelte diff --git a/routes/terminal/[id]/+page.svelte b/src/routes/terminal/[id]/+page.svelte similarity index 100% rename from routes/terminal/[id]/+page.svelte rename to src/routes/terminal/[id]/+page.svelte diff --git a/routes/volumes/+page.svelte b/src/routes/volumes/+page.svelte similarity index 100% rename from routes/volumes/+page.svelte rename to src/routes/volumes/+page.svelte diff --git a/routes/volumes/CloneVolumeModal.svelte b/src/routes/volumes/CloneVolumeModal.svelte similarity index 100% rename from routes/volumes/CloneVolumeModal.svelte rename to src/routes/volumes/CloneVolumeModal.svelte diff --git a/routes/volumes/CreateVolumeModal.svelte b/src/routes/volumes/CreateVolumeModal.svelte similarity index 100% rename from routes/volumes/CreateVolumeModal.svelte rename to src/routes/volumes/CreateVolumeModal.svelte diff --git a/routes/volumes/VolumeBrowserModal.svelte b/src/routes/volumes/VolumeBrowserModal.svelte similarity index 100% rename from routes/volumes/VolumeBrowserModal.svelte rename to src/routes/volumes/VolumeBrowserModal.svelte diff --git a/routes/volumes/VolumeInspectModal.svelte b/src/routes/volumes/VolumeInspectModal.svelte similarity index 100% rename from routes/volumes/VolumeInspectModal.svelte rename to src/routes/volumes/VolumeInspectModal.svelte diff --git a/svelte.config.js b/svelte.config.js new file mode 100644 index 0000000..fb3570f --- /dev/null +++ b/svelte.config.js @@ -0,0 +1,15 @@ +import adapter from 'svelte-adapter-bun'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + preprocess: vitePreprocess(), + + kit: { + adapter: adapter({ + out: 'build' + }) + } +}; + +export default config; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..2c2ed3c --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "rewriteRelativeImportExtensions": true, + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files + // + // To make changes to top-level options such as include and exclude, we recommend extending + // the generated config; see https://svelte.dev/docs/kit/configuration#typescript +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..5f1c578 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,996 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import tailwindcss from '@tailwindcss/vite'; +import { defineConfig, type Plugin } from 'vite'; +import { execSync } from 'child_process'; +import { existsSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; +import { Database } from 'bun:sqlite'; + +const WS_PORT = 5174; + +// ============ Docker Target Types ============ + +interface DockerTarget { + type: 'unix' | 'tcp' | 'hawser-edge'; + socket?: string; + host?: string; + port?: number; + hawserToken?: string; + environmentId?: number; +} + +interface EnvironmentRow { + id: number; + is_local?: boolean | number; + connection_type?: string; + socket_path?: string; + host?: string; + port?: number; + hawser_token?: string; +} + +// ============ Docker Target Resolution ============ + +function resolveDockerTarget( + envId: number | undefined, + getEnvironment: (id: number) => EnvironmentRow | null, + defaultSocketPath: string +): DockerTarget { + if (!envId) return { type: 'unix', socket: defaultSocketPath }; + + const env = getEnvironment(envId); + if (!env) return { type: 'unix', socket: defaultSocketPath }; + + const isLocal = typeof env.is_local === 'boolean' ? env.is_local : Boolean(env.is_local); + if (isLocal || env.connection_type === 'socket' || !env.connection_type) { + return { type: 'unix', socket: env.socket_path || defaultSocketPath }; + } + + if (env.connection_type === 'hawser-edge') { + return { type: 'hawser-edge', environmentId: envId }; + } + + return { + type: 'tcp', + host: env.host || 'localhost', + port: env.port || 2375, + hawserToken: env.connection_type === 'hawser-standard' ? env.hawser_token : undefined + }; +} + +// ============ Exec API Helpers ============ + +function buildExecStartHttpRequest(execId: string, target: DockerTarget): string { + const body = JSON.stringify({ Detach: false, Tty: true }); + const tokenHeader = target.type === 'tcp' && target.hawserToken + ? `X-Hawser-Token: ${target.hawserToken}\r\n` + : ''; + return `POST /exec/${execId}/start HTTP/1.1\r\nHost: localhost\r\nContent-Type: application/json\r\n${tokenHeader}Connection: Upgrade\r\nUpgrade: tcp\r\nContent-Length: ${body.length}\r\n\r\n${body}`; +} + +// ============ Stream Processing ============ + +function processTerminalOutput( + data: string, + state: { headersStripped: boolean; isChunked: boolean } +): string | null { + let text = data; + + if (!state.headersStripped) { + if (text.toLowerCase().includes('transfer-encoding: chunked')) { + state.isChunked = true; + } + const headerEnd = text.indexOf('\r\n\r\n'); + if (headerEnd > -1) { + text = text.slice(headerEnd + 4); + state.headersStripped = true; + } else if (text.startsWith('HTTP/')) { + return null; + } + } + + if (state.isChunked && text) { + text = text.replace(/^[0-9a-fA-F]+\r\n/gm, '').replace(/\r\n$/g, ''); + } + + return text || null; +} + +// ============ Hawser Edge Exec Messages ============ + +function createExecStartMessage(execId: string, containerId: string, shell: string, user: string, cols = 120, rows = 30) { + return { type: 'exec_start', execId, containerId, cmd: shell, user, cols, rows }; +} + +function createExecInputMessage(execId: string, data: string) { + return { type: 'exec_input', execId, data: Buffer.from(data).toString('base64') }; +} + +function createExecResizeMessage(execId: string, cols: number, rows: number) { + return { type: 'exec_resize', execId, cols, rows }; +} + +function createExecEndMessage(execId: string, reason = 'user_closed') { + return { type: 'exec_end', execId, reason }; +} + +// Get build info +function getGitCommit(): string | null { + // Check COMMIT file (created by CI/CD before docker build) + try { + if (existsSync('COMMIT')) { + const commit = require('fs').readFileSync('COMMIT', 'utf-8').trim(); + if (commit && commit !== 'unknown') { + return commit; + } + } + } catch { + // ignore + } + // Fall back to git command (local dev) + try { + return execSync('git rev-parse --short HEAD').toString().trim(); + } catch { + return null; + } +} + +function getGitBranch(): string | null { + // Check BRANCH file (created by CI/CD before docker build) + try { + if (existsSync('BRANCH')) { + const branch = require('fs').readFileSync('BRANCH', 'utf-8').trim(); + if (branch && branch !== 'unknown') { + return branch; + } + } + } catch { + // ignore + } + // Fall back to git command (local dev) + try { + return execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); + } catch { + return null; + } +} + +function getGitTag(): string | null { + // First check env var (set by CI/CD via Docker build-arg) + if (process.env.APP_VERSION) { + return process.env.APP_VERSION; + } + // Check VERSION file (created by CI/CD before docker build) + try { + if (existsSync('VERSION')) { + const version = require('fs').readFileSync('VERSION', 'utf-8').trim(); + if (version && version !== 'unknown') { + return version; + } + } + } catch { + // ignore + } + // Fall back to git tag (local dev) + try { + return execSync('git describe --tags --abbrev=0 2>/dev/null').toString().trim(); + } catch { + return null; + } +} + +// Plugin to externalize bun: protocol modules +function bunExternals(): Plugin { + return { + name: 'bun-externals', + enforce: 'pre', + resolveId(source) { + if (source.startsWith('bun:')) { + return { id: source, external: true }; + } + return null; + } + }; +} + +// Detect Docker socket path +function detectDockerSocket(): string { + if (process.env.DOCKER_SOCKET && existsSync(process.env.DOCKER_SOCKET)) return process.env.DOCKER_SOCKET; + if (process.env.DOCKER_HOST?.startsWith('unix://')) { + const p = process.env.DOCKER_HOST.replace('unix://', ''); + if (existsSync(p)) return p; + } + const candidates = [ + '/var/run/docker.sock', + join(homedir(), '.docker/run/docker.sock'), + join(homedir(), '.orbstack/run/docker.sock'), + '/run/docker.sock' + ]; + for (const s of candidates) { + if (existsSync(s)) return s; + } + return '/var/run/docker.sock'; +} + +// Lazy database connection for environment lookup +let _db: Database | null = null; +function getDb(): Database | null { + if (!_db) { + // Database is in data/db/dockhand.db (same as main app) + const dbPath = join(process.cwd(), 'data', 'db', 'dockhand.db'); + if (existsSync(dbPath)) { + _db = new Database(dbPath, { readonly: true }); + } + } + return _db; +} + +function getEnvironment(id: number): { host: string; port: number; is_local: boolean; connection_type?: string; hawser_token?: string } | null { + const db = getDb(); + if (!db) return null; + const row = db.prepare('SELECT * FROM environments WHERE id = ?').get(id) as any; + return row ? { ...row, is_local: Boolean(row.is_local) } : null; +} + +function getDockerTarget(envId?: number): DockerTarget { + const dockerSocketPath = detectDockerSocket(); + return resolveDockerTarget( + envId, + (id) => getEnvironment(id) as EnvironmentRow | null, + dockerSocketPath + ); +} + +async function createExecForWs(containerId: string, cmd: string[], user: string, target: ReturnType): Promise<{ Id: string }> { + const headers: Record = { 'Content-Type': 'application/json' }; + const fetchOpts: any = { + method: 'POST', + headers, + body: JSON.stringify({ AttachStdin: true, AttachStdout: true, AttachStderr: true, Tty: true, Cmd: cmd, User: user }) + }; + let url: string; + if (target.type === 'unix') { + url = 'http://localhost/containers/' + containerId + '/exec'; + fetchOpts.unix = target.socket; + } else { + url = 'http://' + target.host + ':' + target.port + '/containers/' + containerId + '/exec'; + if (target.hawserToken) { + headers['X-Hawser-Token'] = target.hawserToken; + } + } + const res = await fetch(url, fetchOpts); + if (!res.ok) throw new Error('Failed to create exec: ' + (await res.text())); + return res.json(); +} + +async function resizeExecForWs(execId: string, cols: number, rows: number, target: ReturnType): Promise { + try { + const fetchOpts: any = { method: 'POST' }; + let url: string; + if (target.type === 'unix') { + url = 'http://localhost/exec/' + execId + '/resize?h=' + rows + '&w=' + cols; + fetchOpts.unix = target.socket; + } else { + url = 'http://' + target.host + ':' + target.port + '/exec/' + execId + '/resize?h=' + rows + '&w=' + cols; + if (target.hawserToken) { + fetchOpts.headers = { 'X-Hawser-Token': target.hawserToken }; + } + } + await fetch(url, fetchOpts); + } catch { + // Ignore resize errors + } +} + +// Map to track Docker streams per WebSocket (keyed by unique connection ID) +// Includes WebSocket reference for orphan detection +const dockerStreams = new Map; state: { isChunked: boolean }; ws: any }>(); + +// Counter for unique WebSocket connection IDs +let wsConnectionCounter = 0; + +// Map to track Edge exec sessions (execId -> frontend WebSocket) +const edgeExecSessions = new Map(); + +// Cleanup interval reference - only started in dev mode +let cleanupInterval: ReturnType | null = null; + +// Cleanup function for orphaned sessions +function startCleanupInterval() { + if (cleanupInterval) return; // Already running + + // Cleanup orphaned sessions every 5 minutes to prevent memory leaks + // Only removes sessions where the WebSocket is no longer open (readyState !== 1) + // This catches sessions where close handlers failed to fire + cleanupInterval = setInterval(() => { + let dockerCleaned = 0; + let edgeCleaned = 0; + + for (const [connId, session] of dockerStreams.entries()) { + // readyState: 0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED + if (session.ws?.readyState !== 1) { + try { + session.stream?.end?.(); + } catch { /* ignore */ } + dockerStreams.delete(connId); + dockerCleaned++; + } + } + + for (const [execId, session] of edgeExecSessions.entries()) { + if (session.ws?.readyState !== 1) { + edgeExecSessions.delete(execId); + edgeCleaned++; + } + } + + if (dockerCleaned > 0 || edgeCleaned > 0) { + console.log(`[WS Cleanup] Removed ${dockerCleaned} orphaned docker streams, ${edgeCleaned} orphaned edge sessions`); + } + }, 5 * 60 * 1000); +} + +// Hawser Edge connection types (mirrors hawser.ts) +interface EdgeConnection { + ws: WebSocket; + environmentId: number; + agentId: string; + agentName: string; + agentVersion: string; + dockerVersion: string; + hostname: string; + capabilities: string[]; + connectedAt: Date; + lastHeartbeat: Date; + pendingRequests: Map; + pendingStreamRequests: Map; + pingInterval?: ReturnType; // Server-side ping to keep connection alive through proxies +} + +// Container event from edge agent (matches hawser.ts) +interface ContainerEventData { + containerId: string; + containerName?: string; + image?: string; + action: string; + actorAttributes?: Record; + timestamp: string; +} + +// Metrics data structure from Hawser agent +interface HawserMetrics { + cpuUsage: number; + cpuCores: number; + memoryTotal: number; + memoryUsed: number; + memoryFree: number; + diskTotal: number; + diskUsed: number; + diskFree: number; + networkRxBytes: number; + networkTxBytes: number; +} + +// Use globalThis to share connections with hawser.ts module +declare global { + var __hawserEdgeConnections: Map | undefined; + var __hawserSendMessage: ((envId: number, message: string) => boolean) | undefined; + var __hawserHandleContainerEvent: ((envId: number, event: ContainerEventData) => Promise) | undefined; + var __hawserHandleMetrics: ((envId: number, metrics: HawserMetrics) => Promise) | undefined; +} +const edgeConnections: Map = + globalThis.__hawserEdgeConnections ?? (globalThis.__hawserEdgeConnections = new Map()); + +// Function to send messages through the WebSocket (needed because ws.send must be called from vite context) +globalThis.__hawserSendMessage = (envId: number, message: string): boolean => { + const conn = edgeConnections.get(envId); + if (!conn || !conn.ws) { + return false; + } + + try { + conn.ws.send(message); + return true; + } catch (e) { + console.error(`[Hawser WS] sendMessage error:`, e); + return false; + } +}; + +// Map WebSocket to environmentId for quick lookup on close/message +const wsToEnvId = new Map(); + +// WebSocket server for terminal connections and Hawser Edge in development mode +function webSocketPlugin(): Plugin { + return { + name: 'websocket', + configureServer() { + // Start cleanup interval for dev mode only + startCleanupInterval(); + + const dockerSocketPath = detectDockerSocket(); + console.log(`[Terminal WS] Detected Docker socket at: ${dockerSocketPath}`); + + // Start a Bun.serve WebSocket server on a separate port + Bun.serve({ + port: WS_PORT, + fetch(req, server) { + // Upgrade HTTP requests to WebSocket + if (server.upgrade(req, { data: { url: req.url } })) { + return; // Return nothing if upgrade succeeds + } + return new Response('WebSocket server', { status: 200 }); + }, + websocket: { + async open(ws) { + const url = new URL((ws.data as any).url, `http://localhost:${WS_PORT}`); + + // Check if this is a Hawser Edge connection + if (url.pathname === '/api/hawser/connect') { + console.log('[Hawser WS] New connection pending authentication'); + // Hawser connections wait for hello message to authenticate + return; + } + + // Assign unique connection ID to this WebSocket + const connId = `ws-${++wsConnectionCounter}`; + (ws.data as any).connId = connId; + + // Terminal connection handling + const pathParts = url.pathname.split('/'); + const containerIdIndex = pathParts.indexOf('containers') + 1; + const containerId = pathParts[containerIdIndex]; + + const shell = url.searchParams.get('shell') || '/bin/sh'; + const user = url.searchParams.get('user') || 'root'; + const envIdParam = url.searchParams.get('envId'); + const envId = envIdParam ? parseInt(envIdParam, 10) : undefined; + + if (!containerId) { + ws.send(JSON.stringify({ type: 'error', message: 'No container ID' })); + ws.close(); + return; + } + + const target = getDockerTarget(envId); + console.log('[Terminal WS] Open connId:', connId, 'container:', containerId, 'target:', target.type); + + try { + // Handle Hawser Edge mode differently - use WebSocket protocol + if (target.type === 'hawser-edge') { + const conn = edgeConnections.get(target.environmentId); + if (!conn) { + ws.send(JSON.stringify({ type: 'error', message: 'Edge agent not connected' })); + ws.close(); + return; + } + + // Generate unique exec ID + const execId = crypto.randomUUID(); + console.log('[Terminal WS] Starting Edge exec:', execId, 'container:', containerId); + + // Track this session + edgeExecSessions.set(execId, { ws, execId, environmentId: target.environmentId }); + (ws.data as any).edgeExecId = execId; + + // Send exec_start to the agent (using shared helper) + const execStartMsg = createExecStartMessage(execId, containerId, shell, user); + conn.ws.send(JSON.stringify(execStartMsg)); + return; + } + + // Direct Docker connection (unix or tcp/hawser-standard) + const exec = await createExecForWs(containerId, [shell], user, target); + const execId = exec.Id; + + // Track connection state (using object for mutability across closures) + let headersStripped = false; + const state = { isChunked: false }; + + // Create socket handler for Docker connection + const socketHandler = { + data(socket: any, data: Buffer) { + if (ws.readyState === 1) { + let text = new TextDecoder().decode(data); + // Skip HTTP headers in first response (only once) + if (!headersStripped) { + // Check for chunked encoding in headers + if (text.toLowerCase().includes('transfer-encoding: chunked')) { + state.isChunked = true; + } + const headerEnd = text.indexOf('\r\n\r\n'); + if (headerEnd > -1) { + text = text.slice(headerEnd + 4); + headersStripped = true; + } else if (text.startsWith('HTTP/')) { + // Headers split across packets, skip this entire packet + return; + } + } + // Strip chunked encoding framing if detected + if (state.isChunked && text) { + // Remove chunk size lines (hex number followed by \r\n) + text = text.replace(/^[0-9a-fA-F]+\r\n/gm, '').replace(/\r\n$/g, ''); + } + if (text) { + ws.send(JSON.stringify({ type: 'output', data: text })); + } + } + }, + close() { + if (ws.readyState === 1) { + ws.send(JSON.stringify({ type: 'exit' })); + ws.close(); + } + }, + error() {}, + open(socket: any) { + // Send exec start request (using shared helper) + const httpRequest = buildExecStartHttpRequest(execId, target); + socket.write(httpRequest); + } + }; + + let dockerStream: any; + if (target.type === 'unix') { + dockerStream = await Bun.connect({ unix: target.socket, socket: socketHandler }); + } else if (target.type === 'tcp') { + dockerStream = await Bun.connect({ hostname: target.host, port: target.port, socket: socketHandler }); + } + + dockerStreams.set(connId, { stream: dockerStream, execId, target, state, ws }); + console.log('[Terminal WS] Stream stored for connId:', connId, 'total streams:', dockerStreams.size); + } catch (error: any) { + console.error('[Terminal WS] Error:', error.message); + ws.send(JSON.stringify({ type: 'error', message: error.message })); + ws.close(); + } + }, + async message(ws, message) { + const url = new URL((ws.data as any).url, `http://localhost:${WS_PORT}`); + const connId = (ws.data as any).connId as string | undefined; + console.log('[WS Message] connId:', connId, 'edgeExecId:', (ws.data as any)?.edgeExecId, 'pathname:', url.pathname.slice(0, 50)); + + // Handle Hawser Edge messages + if (url.pathname === '/api/hawser/connect') { + try { + // Debug: Log raw message info + const msgType = typeof message; + const msgLen = typeof message === 'string' ? message.length : + message instanceof ArrayBuffer ? message.byteLength : + (message as Buffer).length || 0; + console.log(`[Hawser WS] Received message: type=${msgType}, length=${msgLen}`); + + // Convert message to string properly (handles both string and ArrayBuffer) + let messageStr: string; + if (typeof message === 'string') { + messageStr = message; + } else if (message instanceof ArrayBuffer) { + messageStr = new TextDecoder().decode(message); + } else if (Buffer.isBuffer(message)) { + messageStr = message.toString('utf-8'); + } else { + // Uint8Array or similar + messageStr = new TextDecoder().decode(new Uint8Array(message as ArrayBuffer)); + } + + console.log(`[Hawser WS] Decoded string length: ${messageStr.length}`); + if (messageStr.length > 0) { + console.log(`[Hawser WS] First 200 chars: ${messageStr.slice(0, 200)}`); + } + + const msg = JSON.parse(messageStr); + console.log(`[Hawser WS] Parsed message type: ${msg.type}`); + await handleHawserMessage(ws, msg); + } catch (error: any) { + console.error('[Hawser WS] Error handling message:', error.message); + // More detailed debug output + const msgType = typeof message; + const msgLen = typeof message === 'string' ? message.length : + message instanceof ArrayBuffer ? message.byteLength : + (message as Buffer).length || 0; + console.error(`[Hawser WS] Message details: type=${msgType}, length=${msgLen}`); + if (typeof message === 'string' && message.length > 0) { + console.error(`[Hawser WS] Message preview: ${message.slice(0, 500)}`); + } else if (message instanceof ArrayBuffer && message.byteLength > 0) { + const preview = new TextDecoder().decode(message.slice(0, 500)); + console.error(`[Hawser WS] ArrayBuffer preview: ${preview}`); + } else if (Buffer.isBuffer(message) && message.length > 0) { + console.error(`[Hawser WS] Buffer preview: ${message.toString('utf-8').slice(0, 500)}`); + } + ws.send(JSON.stringify({ type: 'error', error: error.message })); + } + return; + } + + // Check if this is an Edge exec session + const edgeExecId = (ws.data as any)?.edgeExecId; + if (edgeExecId) { + const session = edgeExecSessions.get(edgeExecId); + if (session) { + const conn = edgeConnections.get(session.environmentId); + if (conn) { + try { + const msg = JSON.parse(message.toString()); + if (msg.type === 'input') { + // Forward input to agent (using shared helper) + conn.ws.send(JSON.stringify(createExecInputMessage(edgeExecId, msg.data))); + } else if (msg.type === 'resize') { + // Forward resize to agent (using shared helper) + conn.ws.send(JSON.stringify(createExecResizeMessage(edgeExecId, msg.cols, msg.rows))); + } + } catch (e) { + console.error('[Terminal WS] Error handling Edge message:', e); + } + } + } + return; + } + + // Terminal message handling (direct Docker connection) + if (!connId) { + console.log('[Terminal WS] No connId for terminal message'); + return; + } + const d = dockerStreams.get(connId); + if (!d) { + console.log('[Terminal WS] No stream for connId:', connId, 'streams:', [...dockerStreams.keys()]); + return; + } + console.log('[Terminal WS] Found stream for connId:', connId); + + try { + const msg = JSON.parse(message.toString()); + if (msg.type === 'input' && d.stream) { + // Always write raw input - chunked encoding only affects reading output + d.stream.write(msg.data); + } else if (msg.type === 'resize' && d.execId) { + resizeExecForWs(d.execId, msg.cols, msg.rows, d.target); + } + } catch { + // If not JSON, treat as raw input + if (d.stream) { + d.stream.write(message); + } + } + }, + close(ws) { + // Check if it's a Hawser connection + const envId = wsToEnvId.get(ws); + if (envId) { + const conn = edgeConnections.get(envId); + if (conn) { + console.log(`[Hawser WS] Agent disconnected: ${conn.agentId}`); + // Clear server-side ping interval + if (conn.pingInterval) { + clearInterval(conn.pingInterval); + conn.pingInterval = undefined; + } + // Reject pending requests + for (const [, pending] of conn.pendingRequests) { + clearTimeout(pending.timeout); + pending.reject(new Error('Connection closed')); + } + // Clean up pending stream requests + for (const [, pending] of conn.pendingStreamRequests) { + pending.onEnd('Connection closed'); + } + edgeConnections.delete(envId); + } + wsToEnvId.delete(ws); + return; + } + + // Check if it's an Edge exec session + const edgeExecId = (ws.data as any)?.edgeExecId; + if (edgeExecId) { + const session = edgeExecSessions.get(edgeExecId); + if (session) { + // Send exec_end to agent (using shared helper) + const conn = edgeConnections.get(session.environmentId); + if (conn) { + conn.ws.send(JSON.stringify(createExecEndMessage(edgeExecId))); + } + edgeExecSessions.delete(edgeExecId); + console.log(`[Terminal WS] Edge exec session closed: ${edgeExecId}`); + } + return; + } + + // Terminal connection cleanup (direct Docker) + const connId = (ws.data as any)?.connId as string | undefined; + if (connId) { + const d = dockerStreams.get(connId); + if (d?.stream) { + d.stream.end(); + } + dockerStreams.delete(connId); + } + } + } + }); + + console.log(`[Terminal WS] WebSocket server running on port ${WS_PORT}`); + } + }; +} + +// Handle Hawser Edge protocol messages +async function handleHawserMessage(ws: any, msg: any) { + if (msg.type === 'hello') { + // Validate token using the app's hawser module + // For dev mode, we'll do a simplified validation + console.log(`[Hawser WS] Hello from agent: ${msg.agentName} (${msg.agentId})`); + + // In dev mode, we need to validate the token against the database + const db = getDb(); + if (!db) { + ws.send(JSON.stringify({ type: 'error', error: 'Database not available' })); + ws.close(); + return; + } + + // Simple token validation (in production this would use argon2 verification) + // For dev mode, just check if a token exists for any environment + const tokens = db.prepare('SELECT * FROM hawser_tokens WHERE is_active = 1').all() as any[]; + + // For dev mode, accept any valid token format and use the first environment with a token + const token = tokens.find((t: any) => msg.token && msg.token.startsWith(t.token_prefix.slice(0, 4))); + + if (!token) { + console.log('[Hawser WS] Invalid token'); + ws.send(JSON.stringify({ type: 'error', error: 'Invalid token' })); + ws.close(); + return; + } + + const environmentId = token.environment_id; + + // Update environment with agent info + try { + db.prepare(`UPDATE environments SET + hawser_last_seen = datetime('now'), + hawser_agent_id = ?, + hawser_agent_name = ?, + hawser_version = ?, + hawser_capabilities = ? + WHERE id = ?`).run( + msg.agentId, + msg.agentName, + msg.version, + JSON.stringify(msg.capabilities || []), + environmentId + ); + } catch (e) { + // Read-only DB in dev mode, ignore + } + + // Close any existing connection for this environment + const existing = edgeConnections.get(environmentId); + if (existing) { + const pendingCount = existing.pendingRequests.size; + const streamCount = existing.pendingStreamRequests.size; + console.log( + `[Hawser WS] Replacing existing connection for environment ${environmentId}. ` + + `Rejecting ${pendingCount} pending requests and ${streamCount} stream requests.` + ); + + // Reject all pending requests before closing + for (const [requestId, pending] of existing.pendingRequests) { + console.log(`[Hawser WS] Rejecting pending request ${requestId} due to connection replacement`); + clearTimeout(pending.timeout); + pending.reject(new Error('Connection replaced by new agent')); + } + for (const [requestId, pending] of existing.pendingStreamRequests) { + console.log(`[Hawser WS] Ending stream request ${requestId} due to connection replacement`); + pending.onEnd?.('Connection replaced by new agent'); + } + existing.pendingRequests.clear(); + existing.pendingStreamRequests.clear(); + + existing.ws.close(1000, 'Replaced by new connection'); + wsToEnvId.delete(existing.ws); + } + + // Store connection in shared map (accessible by hawser.ts via globalThis) + const connection: EdgeConnection = { + ws, + environmentId, + agentId: msg.agentId, + agentName: msg.agentName, + agentVersion: msg.version || 'unknown', + dockerVersion: msg.dockerVersion || 'unknown', + hostname: msg.hostname || 'unknown', + capabilities: msg.capabilities || [], + connectedAt: new Date(), + lastHeartbeat: new Date(), + pendingRequests: new Map(), + pendingStreamRequests: new Map() + }; + + edgeConnections.set(environmentId, connection); + wsToEnvId.set(ws, environmentId); + + // Send welcome + ws.send(JSON.stringify({ + type: 'welcome', + environmentId, + message: `Welcome ${msg.agentName}! Connected to Dockhand dev server.` + })); + + // Start server-side ping interval to keep connection alive through Traefik/proxies + // Traefik has ~10s idle timeout, so we ping every 5 seconds + connection.pingInterval = setInterval(() => { + try { + ws.send(JSON.stringify({ type: 'ping', timestamp: Date.now() })); + } catch (e) { + // Connection likely closed, clear interval + if (connection.pingInterval) { + clearInterval(connection.pingInterval); + connection.pingInterval = undefined; + } + } + }, 5000); + + console.log(`[Hawser WS] Agent ${msg.agentName} connected for environment ${environmentId}`); + } else if (msg.type === 'ping') { + // Agent sent ping - respond with pong to keep connection alive + const envId = wsToEnvId.get(ws); + if (envId) { + const conn = edgeConnections.get(envId); + if (conn) { + conn.lastHeartbeat = new Date(); + } + } + ws.send(JSON.stringify({ type: 'pong', timestamp: Date.now() })); + } else if (msg.type === 'pong') { + // Heartbeat response - update last seen + const envId = wsToEnvId.get(ws); + if (envId) { + const conn = edgeConnections.get(envId); + if (conn) { + conn.lastHeartbeat = new Date(); + } + } + } else if (msg.type === 'response') { + // Response to a request we sent + const envId = wsToEnvId.get(ws); + if (envId) { + const conn = edgeConnections.get(envId); + if (conn) { + const pending = conn.pendingRequests.get(msg.requestId); + if (pending) { + clearTimeout(pending.timeout); + conn.pendingRequests.delete(msg.requestId); + + // Body is now a string (either plain text/JSON or base64-encoded binary) + // isBinary flag indicates if base64 decoding is needed + pending.resolve({ + statusCode: msg.statusCode, + headers: msg.headers || {}, + body: msg.body || '', + isBinary: msg.isBinary || false + }); + } + } + } + } else if (msg.type === 'stream') { + // Streaming data from agent + const envId = wsToEnvId.get(ws); + if (!envId) { + console.warn(`[Hawser WS] Stream data from unknown WebSocket, requestId=${msg.requestId}`); + return; + } + const conn = edgeConnections.get(envId); + if (!conn) { + console.warn(`[Hawser WS] Stream data for unknown environment ${envId}, requestId=${msg.requestId}`); + return; + } + const pending = conn.pendingStreamRequests?.get(msg.requestId); + if (!pending) { + console.warn(`[Hawser WS] Stream data for unknown request ${msg.requestId} on env ${envId}`); + return; + } + pending.onData(msg.data, msg.stream); + } else if (msg.type === 'stream_end') { + // Stream ended + const envId = wsToEnvId.get(ws); + if (!envId) { + console.warn(`[Hawser WS] Stream end from unknown WebSocket, requestId=${msg.requestId}`); + return; + } + const conn = edgeConnections.get(envId); + if (!conn) { + console.warn(`[Hawser WS] Stream end for unknown environment ${envId}, requestId=${msg.requestId}`); + return; + } + const pending = conn.pendingStreamRequests.get(msg.requestId); + if (!pending) { + console.warn(`[Hawser WS] Stream end for unknown request ${msg.requestId} on env ${envId}`); + return; + } + conn.pendingStreamRequests.delete(msg.requestId); + pending.onEnd(msg.reason); + } else if (msg.type === 'metrics') { + // Metrics from agent - save to database for dashboard graphs + const envId = wsToEnvId.get(ws); + if (envId && msg.metrics) { + if (globalThis.__hawserHandleMetrics) { + globalThis.__hawserHandleMetrics(envId, msg.metrics).catch((err) => { + console.error(`[Hawser WS] Error saving metrics:`, err); + }); + } + } + } else if (msg.type === 'exec_ready') { + // Exec session is ready + const session = edgeExecSessions.get(msg.execId); + if (session?.ws?.readyState === 1) { + console.log(`[Hawser WS] Exec ready: ${msg.execId}`); + // Frontend doesn't need explicit ready message, it's already waiting for output + } + } else if (msg.type === 'exec_output') { + // Terminal output from exec session + const session = edgeExecSessions.get(msg.execId); + if (session?.ws?.readyState === 1) { + // Decode base64 data + const data = Buffer.from(msg.data, 'base64').toString('utf-8'); + session.ws.send(JSON.stringify({ type: 'output', data })); + } + } else if (msg.type === 'exec_end') { + // Exec session ended + const session = edgeExecSessions.get(msg.execId); + if (session) { + console.log(`[Hawser WS] Exec ended: ${msg.execId} (reason: ${msg.reason})`); + if (session.ws?.readyState === 1) { + session.ws.send(JSON.stringify({ type: 'exit' })); + session.ws.close(); + } + edgeExecSessions.delete(msg.execId); + } + } else if (msg.type === 'container_event') { + // Container event from edge agent + const envId = wsToEnvId.get(ws); + if (envId && msg.event) { + // Call the global handler registered by hawser.ts + if (globalThis.__hawserHandleContainerEvent) { + globalThis.__hawserHandleContainerEvent(envId, msg.event).catch((err) => { + console.error('[Hawser WS] Error handling container event:', err); + }); + } + } + } else if (msg.type === 'error' && msg.requestId) { + // Error might be for an exec session + const session = edgeExecSessions.get(msg.requestId); + if (session?.ws?.readyState === 1) { + console.error(`[Hawser WS] Exec error: ${msg.error}`); + session.ws.send(JSON.stringify({ type: 'error', message: msg.error })); + session.ws.close(); + edgeExecSessions.delete(msg.requestId); + } + } +} + +export default defineConfig({ + plugins: [bunExternals(), tailwindcss(), sveltekit(), webSocketPlugin()], + define: { + __BUILD_DATE__: JSON.stringify(new Date().toISOString()), + __BUILD_COMMIT__: JSON.stringify(getGitCommit()), + __BUILD_BRANCH__: JSON.stringify(getGitBranch()), + __APP_VERSION__: JSON.stringify(getGitTag()) + }, + optimizeDeps: { + include: ['lucide-svelte', '@xterm/xterm', '@xterm/addon-fit'] + }, + build: { + target: 'esnext', + minify: 'esbuild', + sourcemap: false, + rollupOptions: { + external: [/^bun:/] + } + }, + ssr: { + external: [/^bun:/] + } +});