refactor: update dependencies and remove unused code

- Added new dependencies: `adler2`, `crc32fast`, `flate2`, `miniz_oxide`, and `libredox`.
- Updated existing dependencies: `tokio-rustls` to version 0.26.4 and `filetime` to version 0.2.27.
- Removed the `backup.rs` file as it is no longer needed.
- Introduced tests for configuration and credential management.
- Enhanced the `identity` module to generate W3C compliant DID documents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-12 00:19:30 +00:00
parent 2a867b32a8
commit 6fee6befed
347 changed files with 18703 additions and 46785 deletions

View File

@@ -0,0 +1,172 @@
<template>
<canvas
ref="canvasRef"
class="monitoring-chart"
:width="width"
:height="height"
></canvas>
</template>
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'
export interface ChartDataset {
label: string
data: number[]
color: string
}
const props = withDefaults(
defineProps<{
datasets: ChartDataset[]
labels?: string[]
width?: number
height?: number
yMax?: number
yLabel?: string
showGrid?: boolean
}>(),
{
width: 400,
height: 180,
showGrid: true,
},
)
const canvasRef = ref<HTMLCanvasElement | null>(null)
function draw() {
const canvas = canvasRef.value
if (!canvas) return
const ctx = canvas.getContext('2d')
if (!ctx) return
const dpr = window.devicePixelRatio || 1
canvas.width = props.width * dpr
canvas.height = props.height * dpr
canvas.style.width = `${props.width}px`
canvas.style.height = `${props.height}px`
ctx.scale(dpr, dpr)
const w = props.width
const h = props.height
const pad = { top: 10, right: 12, bottom: 24, left: 44 }
const plotW = w - pad.left - pad.right
const plotH = h - pad.top - pad.bottom
// Clear
ctx.clearRect(0, 0, w, h)
if (!props.datasets.length || !props.datasets[0]?.data.length) {
ctx.fillStyle = 'rgba(255,255,255,0.3)'
ctx.font = '12px system-ui'
ctx.textAlign = 'center'
ctx.fillText('No data yet', w / 2, h / 2)
return
}
// Compute y range
let yMax = props.yMax ?? 0
if (!yMax) {
for (const ds of props.datasets) {
for (const v of ds.data) {
if (v > yMax) yMax = v
}
}
yMax = yMax * 1.1 || 1
}
const maxPoints = Math.max(...props.datasets.map((d) => d.data.length))
// Grid lines
if (props.showGrid) {
ctx.strokeStyle = 'rgba(255,255,255,0.06)'
ctx.lineWidth = 1
const gridCount = 4
for (let i = 0; i <= gridCount; i++) {
const y = pad.top + (plotH / gridCount) * i
ctx.beginPath()
ctx.moveTo(pad.left, y)
ctx.lineTo(pad.left + plotW, y)
ctx.stroke()
}
// Y-axis labels
ctx.fillStyle = 'rgba(255,255,255,0.4)'
ctx.font = '10px system-ui'
ctx.textAlign = 'right'
for (let i = 0; i <= gridCount; i++) {
const y = pad.top + (plotH / gridCount) * i
const val = yMax - (yMax / gridCount) * i
ctx.fillText(formatValue(val), pad.left - 6, y + 3)
}
}
// Draw each dataset
for (const ds of props.datasets) {
if (!ds.data.length) continue
ctx.strokeStyle = ds.color
ctx.lineWidth = 1.5
ctx.lineJoin = 'round'
ctx.lineCap = 'round'
ctx.beginPath()
for (let i = 0; i < ds.data.length; i++) {
const x = pad.left + (i / Math.max(maxPoints - 1, 1)) * plotW
const y = pad.top + plotH - (ds.data[i]! / yMax) * plotH
if (i === 0) {
ctx.moveTo(x, y)
} else {
ctx.lineTo(x, y)
}
}
ctx.stroke()
// Area fill
ctx.globalAlpha = 0.08
ctx.fillStyle = ds.color
ctx.lineTo(pad.left + ((ds.data.length - 1) / Math.max(maxPoints - 1, 1)) * plotW, pad.top + plotH)
ctx.lineTo(pad.left, pad.top + plotH)
ctx.closePath()
ctx.fill()
ctx.globalAlpha = 1.0
}
// X-axis labels (first, middle, last)
if (props.labels && props.labels.length > 0) {
ctx.fillStyle = 'rgba(255,255,255,0.4)'
ctx.font = '10px system-ui'
ctx.textAlign = 'center'
const indices = [0, Math.floor(props.labels.length / 2), props.labels.length - 1]
for (const idx of indices) {
if (idx >= 0 && idx < props.labels.length) {
const x = pad.left + (idx / Math.max(props.labels.length - 1, 1)) * plotW
ctx.fillText(props.labels[idx]!, pad.left + plotW + pad.right > w ? x : x, h - 6)
}
}
}
}
function formatValue(val: number): string {
if (val >= 1_000_000_000) return `${(val / 1_000_000_000).toFixed(1)}G`
if (val >= 1_000_000) return `${(val / 1_000_000).toFixed(1)}M`
if (val >= 1_000) return `${(val / 1_000).toFixed(1)}K`
return val.toFixed(val < 10 ? 1 : 0)
}
watch(
() => [props.datasets, props.labels, props.width, props.height],
() => draw(),
{ deep: true },
)
onMounted(() => {
draw()
window.addEventListener('resize', draw)
})
onUnmounted(() => {
window.removeEventListener('resize', draw)
})
</script>

View File

@@ -46,7 +46,7 @@ onMounted(() => {
// Don't show if already dismissed this session or if already installed
if (sessionStorage.getItem(DISMISS_KEY) === '1') return
if (window.matchMedia('(display-mode: standalone)').matches) return
if ((window.navigator as any).standalone) return
if ((window.navigator as Navigator & { standalone?: boolean }).standalone) return
const handler = (e: Event) => {
e.preventDefault()
@@ -55,11 +55,11 @@ onMounted(() => {
}
window.addEventListener('beforeinstallprompt', handler)
;(window as any).__beforeinstallpromptHandler = handler
;(window as Window & { __beforeinstallpromptHandler?: EventListener }).__beforeinstallpromptHandler = handler
})
onBeforeUnmount(() => {
window.removeEventListener('beforeinstallprompt', (window as any).__beforeinstallpromptHandler)
window.removeEventListener('beforeinstallprompt', (window as Window & { __beforeinstallpromptHandler?: EventListener }).__beforeinstallpromptHandler as EventListener)
})
function dismiss() {

View File

@@ -205,7 +205,7 @@ watch([showWelcome, showLogo], ([welcome, logo]) => {
if ((welcome || logo) && videoElement.value) {
if (videoElement.value.paused) {
videoElement.value.play().catch(err => {
console.warn('Video autoplay failed:', err)
if (import.meta.env.DEV) console.warn('Video autoplay failed:', err)
})
}
// Add pause prevention handler once, remove when no longer needed
@@ -228,7 +228,7 @@ watch(showWelcome, (isShowing) => {
if (isShowing && videoElement.value) {
// Start video immediately when welcome appears
videoElement.value.play().catch(err => {
console.warn('Video autoplay failed on welcome:', err)
if (import.meta.env.DEV) console.warn('Video autoplay failed on welcome:', err)
})
}
})
@@ -414,7 +414,7 @@ function startAlienIntro() {
playWelcomeNoderunnerSpeech()
if (videoElement.value) {
videoElement.value.play().catch(err => {
console.warn('Video autoplay failed on welcome:', err)
if (import.meta.env.DEV) console.warn('Video autoplay failed on welcome:', err)
})
}
backgroundOpacity.value = 0.3

View File

@@ -0,0 +1,117 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import LineChart from '../LineChart.vue'
// Mock canvas context
const mockContext = {
clearRect: vi.fn(),
beginPath: vi.fn(),
moveTo: vi.fn(),
lineTo: vi.fn(),
stroke: vi.fn(),
fill: vi.fn(),
fillRect: vi.fn(),
fillText: vi.fn(),
closePath: vi.fn(),
setLineDash: vi.fn(),
save: vi.fn(),
restore: vi.fn(),
scale: vi.fn(),
createLinearGradient: vi.fn().mockReturnValue({
addColorStop: vi.fn(),
}),
canvas: { width: 600, height: 200 },
strokeStyle: '',
fillStyle: '',
lineWidth: 0,
font: '',
textAlign: '',
textBaseline: '',
globalAlpha: 1,
}
beforeEach(() => {
vi.clearAllMocks()
HTMLCanvasElement.prototype.getContext = vi.fn().mockReturnValue(mockContext)
})
describe('LineChart', () => {
const sampleDatasets = [
{ label: 'CPU', data: [10, 20, 30, 40, 50], color: '#fb923c' },
]
it('renders a canvas element', () => {
const wrapper = shallowMount(LineChart, {
props: { datasets: sampleDatasets },
})
expect(wrapper.find('canvas').exists()).toBe(true)
})
it('accepts datasets prop', () => {
const wrapper = shallowMount(LineChart, {
props: { datasets: sampleDatasets },
})
expect(wrapper.exists()).toBe(true)
})
it('renders with empty datasets', () => {
const wrapper = shallowMount(LineChart, {
props: { datasets: [] },
})
expect(wrapper.find('canvas').exists()).toBe(true)
})
it('renders with multiple datasets', () => {
const wrapper = shallowMount(LineChart, {
props: {
datasets: [
{ label: 'CPU', data: [10, 20, 30], color: '#fb923c' },
{ label: 'Memory', data: [50, 60, 70], color: '#4ade80' },
],
},
})
expect(wrapper.exists()).toBe(true)
})
it('accepts optional height and width props', () => {
const wrapper = shallowMount(LineChart, {
props: {
datasets: sampleDatasets,
height: 300,
width: 600,
},
})
const canvas = wrapper.find('canvas')
expect(canvas.attributes('width')).toBe('600')
expect(canvas.attributes('height')).toBe('300')
})
it('uses default width of 400 and height of 180', () => {
const wrapper = shallowMount(LineChart, {
props: { datasets: sampleDatasets },
})
const canvas = wrapper.find('canvas')
expect(canvas.attributes('width')).toBe('400')
expect(canvas.attributes('height')).toBe('180')
})
it('renders with dataset containing single data point', () => {
const wrapper = shallowMount(LineChart, {
props: {
datasets: [{ label: 'Test', data: [42], color: '#3b82f6' }],
},
})
expect(wrapper.exists()).toBe(true)
})
it('accepts yMax and yLabel props', () => {
const wrapper = shallowMount(LineChart, {
props: {
datasets: sampleDatasets,
yMax: 100,
yLabel: 'Percent',
},
})
expect(wrapper.exists()).toBe(true)
})
})

View File

@@ -0,0 +1,103 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import PWAInstallPrompt from '../PWAInstallPrompt.vue'
describe('PWAInstallPrompt', () => {
beforeEach(() => {
vi.clearAllMocks()
sessionStorage.clear()
// Mock matchMedia to return non-standalone
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation((query: string) => ({
matches: false,
media: query,
onchange: null,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
addListener: vi.fn(),
removeListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
})
})
it('renders without errors', () => {
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
expect(wrapper.exists()).toBe(true)
})
it('does not show prompt initially', () => {
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
expect(wrapper.text()).not.toContain('Install Archipelago')
})
it('shows prompt after beforeinstallprompt event', async () => {
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
// Fire the beforeinstallprompt event
const event = new Event('beforeinstallprompt')
Object.defineProperty(event, 'preventDefault', { value: vi.fn() })
window.dispatchEvent(event)
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Install Archipelago')
})
it('hides prompt when dismissed', async () => {
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
// Show prompt
const event = new Event('beforeinstallprompt')
Object.defineProperty(event, 'preventDefault', { value: vi.fn() })
window.dispatchEvent(event)
await wrapper.vm.$nextTick()
// Click dismiss button
const dismissBtn = wrapper.findAll('button').find(b => b.text().includes('Not now'))
expect(dismissBtn).toBeDefined()
await dismissBtn!.trigger('click')
expect(sessionStorage.getItem('archipelago_pwa_install_dismissed')).toBe('1')
})
it('does not show if already dismissed this session', async () => {
sessionStorage.setItem('archipelago_pwa_install_dismissed', '1')
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
// Fire beforeinstallprompt — should not show
const event = new Event('beforeinstallprompt')
Object.defineProperty(event, 'preventDefault', { value: vi.fn() })
window.dispatchEvent(event)
await wrapper.vm.$nextTick()
expect(wrapper.text()).not.toContain('Install Archipelago')
})
it('does not show in standalone mode', async () => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockReturnValue({ matches: true }),
})
const wrapper = shallowMount(PWAInstallPrompt, {
global: { stubs: { Teleport: true, Transition: true } },
})
const event = new Event('beforeinstallprompt')
Object.defineProperty(event, 'preventDefault', { value: vi.fn() })
window.dispatchEvent(event)
await wrapper.vm.$nextTick()
expect(wrapper.text()).not.toContain('Install Archipelago')
})
})