diff --git a/package.json b/package.json index 196c30c..45523e1 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "devDependencies": { "@eslint/compat": "^2.0.3", "@eslint/js": "^9.39.4", - "@iconify-json/material-symbols": "^1.2.60", + "@iconify-json/material-symbols": "^1.2.61", "@noble/hashes": "^2.0.1", "@sveltejs/adapter-node": "^5.5.4", "@sveltejs/kit": "^2.53.4", @@ -35,7 +35,7 @@ "es-hangul": "^2.3.8", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-svelte": "^3.15.0", + "eslint-plugin-svelte": "^3.15.2", "eslint-plugin-tailwindcss": "^3.18.2", "exifreader": "^4.36.2", "file-saver": "^2.0.5", @@ -48,11 +48,11 @@ "prettier": "^3.8.1", "prettier-plugin-svelte": "^3.5.1", "prettier-plugin-tailwindcss": "^0.7.2", - "svelte": "^5.53.7", + "svelte": "^5.53.9", "svelte-check": "^4.4.5", "tailwindcss": "^3.4.19", "typescript": "^5.9.3", - "typescript-eslint": "^8.56.1", + "typescript-eslint": "^8.57.0", "unplugin-icons": "^23.0.1", "vite": "^7.3.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a269efc..3c4b976 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -43,23 +43,23 @@ importers: specifier: ^9.39.4 version: 9.39.4 '@iconify-json/material-symbols': - specifier: ^1.2.60 - version: 1.2.60 + specifier: ^1.2.61 + version: 1.2.61 '@noble/hashes': specifier: ^2.0.1 version: 2.0.1 '@sveltejs/adapter-node': specifier: ^5.5.4 - version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0))) + version: 5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0))) '@sveltejs/kit': specifier: ^2.53.4 - version: 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + version: 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) '@sveltejs/vite-plugin-svelte': specifier: ^6.2.4 - version: 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + version: 6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) '@tanstack/svelte-virtual': specifier: ^3.13.21 - version: 3.13.21(svelte@5.53.7) + version: 3.13.21(svelte@5.53.9) '@trpc/client': specifier: ^11.12.0 version: 11.12.0(@trpc/server@11.12.0(typescript@5.9.3))(typescript@5.9.3) @@ -94,8 +94,8 @@ importers: specifier: ^10.1.8 version: 10.1.8(eslint@9.39.4(jiti@1.21.7)) eslint-plugin-svelte: - specifier: ^3.15.0 - version: 3.15.0(eslint@9.39.4(jiti@1.21.7))(svelte@5.53.7) + specifier: ^3.15.2 + version: 3.15.2(eslint@9.39.4(jiti@1.21.7))(svelte@5.53.9) eslint-plugin-tailwindcss: specifier: ^3.18.2 version: 3.18.2(tailwindcss@3.4.19(yaml@2.8.0)) @@ -128,16 +128,16 @@ importers: version: 3.8.1 prettier-plugin-svelte: specifier: ^3.5.1 - version: 3.5.1(prettier@3.8.1)(svelte@5.53.7) + version: 3.5.1(prettier@3.8.1)(svelte@5.53.9) prettier-plugin-tailwindcss: specifier: ^0.7.2 - version: 0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.7))(prettier@3.8.1) + version: 0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.9))(prettier@3.8.1) svelte: - specifier: ^5.53.7 - version: 5.53.7 + specifier: ^5.53.9 + version: 5.53.9 svelte-check: specifier: ^4.4.5 - version: 4.4.5(picomatch@4.0.3)(svelte@5.53.7)(typescript@5.9.3) + version: 4.4.5(picomatch@4.0.3)(svelte@5.53.9)(typescript@5.9.3) tailwindcss: specifier: ^3.4.19 version: 3.4.19(yaml@2.8.0) @@ -145,14 +145,14 @@ importers: specifier: ^5.9.3 version: 5.9.3 typescript-eslint: - specifier: ^8.56.1 - version: 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + specifier: ^8.57.0 + version: 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) unplugin-icons: specifier: ^23.0.1 - version: 23.0.1(svelte@5.53.7) + version: 23.0.1(svelte@5.53.9) vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0) + version: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0) packages: @@ -389,8 +389,8 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@iconify-json/material-symbols@1.2.60': - resolution: {integrity: sha512-bmVrnz/9KJNh/j+nO3pyxzo0h8iENIKxv5RASDURhjKdPI53rRcKN7E2Gmwi25k9CBJ+IC6L9l0AGgngeqyRuw==} + '@iconify-json/material-symbols@1.2.61': + resolution: {integrity: sha512-zzk6utjXKTyUZxbtv6GQ6227WZDinN6xKcdMIM9F6CS+bmt1Zcqs8PKWKChcvexDkEe5zqkVqUsUhhNW/WaGzQ==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -692,8 +692,8 @@ packages: '@types/node-schedule@2.1.8': resolution: {integrity: sha512-k00g6Yj/oUg/CDC+MeLHUzu0+OFxWbIqrFfDiLi6OPKxTujvpv29mHGM8GtKr7B+9Vv92FcK/8mRqi1DK5f3hA==} - '@types/node@25.3.5': - resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==} + '@types/node@25.4.0': + resolution: {integrity: sha512-9wLpoeWuBlcbBpOY3XmzSTG3oscB6xjBEEtn+pYXTfhyXhIxC5FsBer2KTopBlvKEiW9l13po9fq+SJY/5lkhw==} '@types/pg@8.18.0': resolution: {integrity: sha512-gT+oueVQkqnj6ajGJXblFR4iavIXWsGAFCk3dP4Kki5+a9R4NMt0JARdk6s8cUKcfUoqP5dAtDSLU8xYUTFV+Q==} @@ -704,63 +704,63 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - '@typescript-eslint/eslint-plugin@8.56.1': - resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + '@typescript-eslint/eslint-plugin@8.57.0': + resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.56.1 + '@typescript-eslint/parser': ^8.57.0 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/parser@8.56.1': - resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + '@typescript-eslint/parser@8.57.0': + resolution: {integrity: sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.56.1': - resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + '@typescript-eslint/project-service@8.57.0': + resolution: {integrity: sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/scope-manager@8.56.1': - resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + '@typescript-eslint/scope-manager@8.57.0': + resolution: {integrity: sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.56.1': - resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + '@typescript-eslint/tsconfig-utils@8.57.0': + resolution: {integrity: sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/type-utils@8.56.1': - resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + '@typescript-eslint/type-utils@8.57.0': + resolution: {integrity: sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@8.56.1': - resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + '@typescript-eslint/types@8.57.0': + resolution: {integrity: sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.56.1': - resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + '@typescript-eslint/typescript-estree@8.57.0': + resolution: {integrity: sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.56.1': - resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + '@typescript-eslint/utils@8.57.0': + resolution: {integrity: sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@8.56.1': - resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + '@typescript-eslint/visitor-keys@8.57.0': + resolution: {integrity: sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@xmldom/xmldom@0.9.8': @@ -1047,8 +1047,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-svelte@3.15.0: - resolution: {integrity: sha512-QKB7zqfuB8aChOfBTComgDptMf2yxiJx7FE04nneCmtQzgTHvY8UJkuh8J2Rz7KB9FFV9aTHX6r7rdYGvG8T9Q==} + eslint-plugin-svelte@3.15.2: + resolution: {integrity: sha512-k4Nsjs3bHujeEnnckoTM4mFYR1e8Mb9l2rTwNdmYiamA+Tjzn8X+2F+fuSP2w4VbXYhn2bmySyACQYdmUDW2Cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 @@ -1168,8 +1168,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.4.0: - resolution: {integrity: sha512-kC6Bb+ooptOIvWj5B63EQWkF0FEnNjV2ZNkLMLZRDDduIiWeFF4iKnslwhiWxjAdbg4NzTNo6h0qLuvFrcx+Sw==} + flatted@3.4.1: + resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} @@ -1886,8 +1886,8 @@ packages: svelte: optional: true - svelte@5.53.7: - resolution: {integrity: sha512-uxck1KI7JWtlfP3H6HOWi/94soAl23jsGJkBzN2BAWcQng0+lTrRNhxActFqORgnO9BHVd1hKJhG+ljRuIUWfQ==} + svelte@5.53.9: + resolution: {integrity: sha512-MwDfWsN8qZzeP0jlQsWF4k/4B3csb3IbzCRggF+L/QqY7T8bbKvnChEo1cPZztF51HJQhilDbevWYl2LvXbquA==} engines: {node: '>=18'} tailwindcss@3.4.19: @@ -1941,8 +1941,8 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.56.1: - resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==} + typescript-eslint@8.57.0: + resolution: {integrity: sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 @@ -2239,7 +2239,7 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@iconify-json/material-symbols@1.2.60': + '@iconify-json/material-symbols@1.2.61': dependencies: '@iconify/types': 2.0.0 @@ -2405,19 +2405,19 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-node@5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))': + '@sveltejs/adapter-node@5.5.4(@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))': dependencies: '@rollup/plugin-commonjs': 29.0.2(rollup@4.59.0) '@rollup/plugin-json': 6.1.0(rollup@4.59.0) '@rollup/plugin-node-resolve': 16.0.3(rollup@4.59.0) - '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + '@sveltejs/kit': 2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) rollup: 4.59.0 - '@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0))': + '@sveltejs/kit@2.53.4(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(typescript@5.9.3)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -2428,32 +2428,32 @@ snapshots: mrmime: 2.0.1 set-cookie-parser: 3.0.1 sirv: 3.0.2 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0) + svelte: 5.53.9 + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0) optionalDependencies: typescript: 5.9.3 - '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) obug: 2.1.1 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0) + svelte: 5.53.9 + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0) - '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0))': + '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.7)(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)))(svelte@5.53.9)(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.53.7 - vite: 7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0) - vitefu: 1.1.2(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)) + svelte: 5.53.9 + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0) + vitefu: 1.1.2(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)) - '@tanstack/svelte-virtual@3.13.21(svelte@5.53.7)': + '@tanstack/svelte-virtual@3.13.21(svelte@5.53.9)': dependencies: '@tanstack/virtual-core': 3.13.21 - svelte: 5.53.7 + svelte: 5.53.9 '@tanstack/virtual-core@3.13.21': {} @@ -2478,15 +2478,15 @@ snapshots: '@types/node-schedule@2.1.8': dependencies: - '@types/node': 25.3.5 + '@types/node': 25.4.0 - '@types/node@25.3.5': + '@types/node@25.4.0': dependencies: undici-types: 7.18.2 '@types/pg@8.18.0': dependencies: - '@types/node': 25.3.5 + '@types/node': 25.4.0 pg-protocol: 1.13.0 pg-types: 2.2.0 @@ -2494,14 +2494,14 @@ snapshots: '@types/trusted-types@2.0.7': {} - '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/type-utils': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/type-utils': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.0 eslint: 9.39.4(jiti@1.21.7) ignore: 7.0.5 natural-compare: 1.4.0 @@ -2510,41 +2510,41 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 eslint: 9.39.4(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': + '@typescript-eslint/project-service@8.57.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 debug: 4.4.3 typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.56.1': + '@typescript-eslint/scope-manager@8.57.0': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/visitor-keys': 8.57.0 - '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.57.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.4(jiti@1.21.7) ts-api-utils: 2.4.0(typescript@5.9.3) @@ -2552,14 +2552,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.56.1': {} + '@typescript-eslint/types@8.57.0': {} - '@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.57.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.56.1(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/visitor-keys': 8.56.1 + '@typescript-eslint/project-service': 8.57.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/visitor-keys': 8.57.0 debug: 4.4.3 minimatch: 10.2.4 semver: 7.7.4 @@ -2569,20 +2569,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': + '@typescript-eslint/utils@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) - '@typescript-eslint/scope-manager': 8.56.1 - '@typescript-eslint/types': 8.56.1 - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.57.0 + '@typescript-eslint/types': 8.57.0 + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) eslint: 9.39.4(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.56.1': + '@typescript-eslint/visitor-keys@8.57.0': dependencies: - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/types': 8.57.0 eslint-visitor-keys: 5.0.1 '@xmldom/xmldom@0.9.8': @@ -2865,7 +2865,7 @@ snapshots: dependencies: eslint: 9.39.4(jiti@1.21.7) - eslint-plugin-svelte@3.15.0(eslint@9.39.4(jiti@1.21.7))(svelte@5.53.7): + eslint-plugin-svelte@3.15.2(eslint@9.39.4(jiti@1.21.7))(svelte@5.53.9): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@1.21.7)) '@jridgewell/sourcemap-codec': 1.5.5 @@ -2877,9 +2877,9 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.8) postcss-safe-parser: 7.0.1(postcss@8.5.8) semver: 7.7.4 - svelte-eslint-parser: 1.6.0(svelte@5.53.7) + svelte-eslint-parser: 1.6.0(svelte@5.53.9) optionalDependencies: - svelte: 5.53.7 + svelte: 5.53.9 transitivePeerDependencies: - ts-node @@ -3012,10 +3012,10 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.4.0 + flatted: 3.4.1 keyv: 4.5.4 - flatted@3.4.0: {} + flatted@3.4.1: {} follow-redirects@1.15.11: {} @@ -3457,16 +3457,16 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.7): + prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.9): dependencies: prettier: 3.8.1 - svelte: 5.53.7 + svelte: 5.53.9 - prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.7))(prettier@3.8.1): + prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.53.9))(prettier@3.8.1): dependencies: prettier: 3.8.1 optionalDependencies: - prettier-plugin-svelte: 3.5.1(prettier@3.8.1)(svelte@5.53.7) + prettier-plugin-svelte: 3.5.1(prettier@3.8.1)(svelte@5.53.9) prettier@3.8.1: {} @@ -3590,19 +3590,19 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-check@4.4.5(picomatch@4.0.3)(svelte@5.53.7)(typescript@5.9.3): + svelte-check@4.4.5(picomatch@4.0.3)(svelte@5.53.9)(typescript@5.9.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.3) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.53.7 + svelte: 5.53.9 typescript: 5.9.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.6.0(svelte@5.53.7): + svelte-eslint-parser@1.6.0(svelte@5.53.9): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -3612,9 +3612,9 @@ snapshots: postcss-selector-parser: 7.1.1 semver: 7.7.4 optionalDependencies: - svelte: 5.53.7 + svelte: 5.53.9 - svelte@5.53.7: + svelte@5.53.9: dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -3696,12 +3696,12 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3): + typescript-eslint@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/parser': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.56.1(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.57.0(@typescript-eslint/parser@8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3))(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/parser': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.9.3) eslint: 9.39.4(jiti@1.21.7) typescript: 5.9.3 transitivePeerDependencies: @@ -3713,7 +3713,7 @@ snapshots: undici-types@7.18.2: {} - unplugin-icons@23.0.1(svelte@5.53.7): + unplugin-icons@23.0.1(svelte@5.53.9): dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/utils': 3.1.0 @@ -3721,7 +3721,7 @@ snapshots: obug: 2.1.1 unplugin: 2.3.11 optionalDependencies: - svelte: 5.53.7 + svelte: 5.53.9 unplugin@2.3.11: dependencies: @@ -3744,7 +3744,7 @@ snapshots: uuid@13.0.0: {} - vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0): + vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0): dependencies: esbuild: 0.27.3 fdir: 6.5.0(picomatch@4.0.3) @@ -3753,14 +3753,14 @@ snapshots: rollup: 4.59.0 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 25.3.5 + '@types/node': 25.4.0 fsevents: 2.3.3 jiti: 1.21.7 yaml: 2.8.0 - vitefu@1.1.2(vite@7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0)): + vitefu@1.1.2(vite@7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0)): optionalDependencies: - vite: 7.3.1(@types/node@25.3.5)(jiti@1.21.7)(yaml@2.8.0) + vite: 7.3.1(@types/node@25.4.0)(jiti@1.21.7)(yaml@2.8.0) webpack-virtual-modules@0.6.2: {} diff --git a/src/lib/server/db/error.ts b/src/lib/server/db/error.ts index 0ca6ec2..ea5d1b6 100644 --- a/src/lib/server/db/error.ts +++ b/src/lib/server/db/error.ts @@ -11,7 +11,6 @@ type IntegrityErrorMessages = | "Directory already favorited" | "Directory not favorited" | "File not found" - | "File is not legacy" | "File not found in category" | "File already added to category" | "File already favorited" diff --git a/src/lib/server/db/file.ts b/src/lib/server/db/file.ts index 4ad88ab..68f5b0c 100644 --- a/src/lib/server/db/file.ts +++ b/src/lib/server/db/file.ts @@ -141,17 +141,6 @@ export const getAllFileIds = async (userId: number) => { return files.map(({ id }) => id); }; -export const getLegacyFiles = async (userId: number, limit: number = 100) => { - const files = await db - .selectFrom("file") - .selectAll() - .where("user_id", "=", userId) - .where("encrypted_content_iv", "is not", null) - .limit(limit) - .execute(); - return files.map(toFile); -}; - export const getFilesWithoutThumbnail = async (userId: number, limit: number = 100) => { const files = await db .selectFrom("file") @@ -416,51 +405,6 @@ export const unregisterFile = async (userId: number, fileId: number) => { }); }; -export const migrateFileContent = async ( - trx: typeof db, - userId: number, - fileId: number, - newPath: string, - dekVersion: Date, - encContentHash: string, -) => { - const file = await trx - .selectFrom("file") - .select(["path", "data_encryption_key_version", "encrypted_content_iv"]) - .where("id", "=", fileId) - .where("user_id", "=", userId) - .limit(1) - .forUpdate() - .executeTakeFirst(); - if (!file) { - throw new IntegrityError("File not found"); - } else if (file.data_encryption_key_version.getTime() !== dekVersion.getTime()) { - throw new IntegrityError("Invalid DEK version"); - } else if (!file.encrypted_content_iv) { - throw new IntegrityError("File is not legacy"); - } - - await trx - .updateTable("file") - .set({ - path: newPath, - encrypted_content_iv: null, - encrypted_content_hash: encContentHash, - }) - .where("id", "=", fileId) - .where("user_id", "=", userId) - .execute(); - await trx - .insertInto("file_log") - .values({ - file_id: fileId, - timestamp: new Date(), - action: "migrate", - }) - .execute(); - return { oldPath: file.path }; -}; - export const addFileToCategory = async (fileId: number, categoryId: number) => { await db.transaction().execute(async (trx) => { try { diff --git a/src/lib/server/db/schema/upload.ts b/src/lib/server/db/schema/upload.ts index b9c8510..9d07cda 100644 --- a/src/lib/server/db/schema/upload.ts +++ b/src/lib/server/db/schema/upload.ts @@ -3,7 +3,7 @@ import type { Ciphertext } from "./utils"; export interface UploadSessionTable { id: string; - type: "file" | "thumbnail" | "migration"; + type: "file" | "thumbnail"; user_id: number; path: string; bitmap: Buffer; diff --git a/src/lib/server/db/upload.ts b/src/lib/server/db/upload.ts index 9dd85a0..9c39649 100644 --- a/src/lib/server/db/upload.ts +++ b/src/lib/server/db/upload.ts @@ -26,8 +26,8 @@ interface FileUploadSession extends BaseUploadSession { encLastModifiedAt: Ciphertext; } -interface ThumbnailOrMigrationUploadSession extends BaseUploadSession { - type: "thumbnail" | "migration"; +interface ThumbnailUploadSession extends BaseUploadSession { + type: "thumbnail"; fileId: number; dekVersion: Date; } @@ -86,8 +86,8 @@ export const createFileUploadSession = async ( }); }; -export const createThumbnailOrMigrationUploadSession = async ( - params: Omit, +export const createThumbnailUploadSession = async ( + params: Omit, ) => { await db.transaction().execute(async (trx) => { const file = await trx @@ -164,7 +164,7 @@ export const getUploadSession = async (sessionId: string, userId: number) => { expiresAt: session.expires_at, fileId: session.file_id!, dekVersion: session.data_encryption_key_version!, - } satisfies ThumbnailOrMigrationUploadSession; + } satisfies ThumbnailUploadSession; } }; diff --git a/src/routes/(fullscreen)/settings/migration/+page.server.ts b/src/routes/(fullscreen)/settings/migration/+page.server.ts deleted file mode 100644 index 3e1c32a..0000000 --- a/src/routes/(fullscreen)/settings/migration/+page.server.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createCaller } from "$trpc/router.server"; -import type { PageServerLoad } from "./$types"; - -export const load: PageServerLoad = async (event) => { - const files = await createCaller(event).file.listLegacy(); - return { files }; -}; diff --git a/src/routes/(fullscreen)/settings/migration/+page.svelte b/src/routes/(fullscreen)/settings/migration/+page.svelte deleted file mode 100644 index 87450d1..0000000 --- a/src/routes/(fullscreen)/settings/migration/+page.svelte +++ /dev/null @@ -1,82 +0,0 @@ - - - - 암호화 마이그레이션 - - - - - {#if files.length > 0} -
-

- 이전 버전의 ArkVault에서 업로드된 {files.length}개 파일을 다시 암호화할 수 있어요. -

-
- {#each files as { info, state } (info.id)} - {#if info.exists} - goto(`/file/${id}`)} - onMigrateClick={requestFileMigration} - /> - {/if} - {/each} -
-
- - - - {:else} -
-

- {#if data.files.length === 0} - 마이그레이션할 파일이 없어요. - {:else} - 파일 목록을 불러오고 있어요. - {/if} -

-
- {/if} -
diff --git a/src/routes/(fullscreen)/settings/migration/File.svelte b/src/routes/(fullscreen)/settings/migration/File.svelte deleted file mode 100644 index d16e800..0000000 --- a/src/routes/(fullscreen)/settings/migration/File.svelte +++ /dev/null @@ -1,52 +0,0 @@ - - - - - onclick(info)} - actionButtonIcon={!state || state.status === "error" ? IconSync : undefined} - onActionButtonClick={() => onMigrateClick(info)} - actionButtonClass="text-gray-800" -> - - diff --git a/src/routes/(fullscreen)/settings/migration/service.svelte.ts b/src/routes/(fullscreen)/settings/migration/service.svelte.ts deleted file mode 100644 index cc4bc7f..0000000 --- a/src/routes/(fullscreen)/settings/migration/service.svelte.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { limitFunction } from "p-limit"; -import { SvelteMap } from "svelte/reactivity"; -import { CHUNK_SIZE } from "$lib/constants"; -import { getFileInfo, type FileInfo } from "$lib/modules/filesystem"; -import { uploadBlob } from "$lib/modules/upload"; -import { requestFileDownload } from "$lib/services/file"; -import { HybridPromise, Scheduler } from "$lib/utils"; -import { trpc } from "$trpc/client"; -import type { RouterOutputs } from "$trpc/router.server"; - -export type MigrationStatus = - | "queued" - | "downloading" - | "upload-pending" - | "uploading" - | "uploaded" - | "error"; - -export interface MigrationState { - status: MigrationStatus; - progress?: number; - rate?: number; -} - -const scheduler = new Scheduler(); -const states = new SvelteMap(); - -export const requestLegacyFiles = async ( - filesRaw: RouterOutputs["file"]["listLegacy"], - masterKey: CryptoKey, -) => { - const files = await HybridPromise.all( - filesRaw.map((file) => getFileInfo(file.id, masterKey, { serverResponse: file })), - ); - return files; -}; - -const createState = (status: MigrationStatus): MigrationState => { - const state = $state({ status }); - return state; -}; - -export const getMigrationState = (fileId: number) => { - return states.get(fileId); -}; - -export const clearMigrationStates = () => { - for (const [id, state] of states) { - if (state.status === "uploaded" || state.status === "error") { - states.delete(id); - } - } -}; - -const requestFileUpload = limitFunction( - async ( - state: MigrationState, - fileId: number, - fileBuffer: ArrayBuffer, - dataKey: CryptoKey, - dataKeyVersion: Date, - ) => { - state.status = "uploading"; - - const { uploadId } = await trpc().upload.startMigrationUpload.mutate({ - file: fileId, - chunks: Math.ceil(fileBuffer.byteLength / CHUNK_SIZE), - dekVersion: dataKeyVersion, - }); - - await uploadBlob(uploadId, new Blob([fileBuffer]), dataKey, { - onProgress(s) { - state.progress = s.progress; - state.rate = s.rate; - }, - }); - - await trpc().upload.completeMigrationUpload.mutate({ uploadId }); - state.status = "uploaded"; - }, - { concurrency: 1 }, -); - -export const requestFileMigration = async (fileInfo: FileInfo) => { - let state = states.get(fileInfo.id); - if (state) { - if (state.status !== "error") return; - state.status = "queued"; - state.progress = undefined; - state.rate = undefined; - } else { - state = createState("queued"); - states.set(fileInfo.id, state); - } - - try { - const dataKey = fileInfo.dataKey; - if (!dataKey) { - throw new Error("Data key not available"); - } - - let fileBuffer: ArrayBuffer | undefined; - - await scheduler.schedule( - async () => { - state.status = "downloading"; - fileBuffer = await requestFileDownload(fileInfo.id, dataKey.key, true); - return fileBuffer.byteLength; - }, - () => requestFileUpload(state, fileInfo.id, fileBuffer!, dataKey.key, dataKey.version), - ); - } catch (e) { - state.status = "error"; - throw e; - } -}; diff --git a/src/routes/(main)/menu/+page.svelte b/src/routes/(main)/menu/+page.svelte index 2bfd3fc..40f4a26 100644 --- a/src/routes/(main)/menu/+page.svelte +++ b/src/routes/(main)/menu/+page.svelte @@ -5,7 +5,6 @@ import IconStorage from "~icons/material-symbols/storage"; import IconImage from "~icons/material-symbols/image"; - import IconLockReset from "~icons/material-symbols/lock-reset"; import IconPassword from "~icons/material-symbols/password"; import IconLogout from "~icons/material-symbols/logout"; @@ -42,13 +41,6 @@ > 썸네일 - goto("/settings/migration")} - icon={IconLockReset} - iconColor="text-teal-500" - > - 암호화 마이그레이션 -

보안

diff --git a/src/trpc/routers/file.ts b/src/trpc/routers/file.ts index 30aaacd..679d790 100644 --- a/src/trpc/routers/file.ts +++ b/src/trpc/routers/file.ts @@ -118,26 +118,6 @@ const fileRouter = router({ })); }), - listLegacy: roleProcedure["activeClient"].query(async ({ ctx }) => { - const files = await FileRepo.getLegacyFiles(ctx.session.userId); - return files.map((file) => ({ - id: file.id, - isLegacy: true, - parent: file.parentId, - mekVersion: file.mekVersion, - dek: file.encDek, - dekVersion: file.dekVersion, - contentType: file.contentType, - name: file.encName.ciphertext, - nameIv: file.encName.iv, - createdAt: file.encCreatedAt?.ciphertext, - createdAtIv: file.encCreatedAt?.iv, - lastModifiedAt: file.encLastModifiedAt.ciphertext, - lastModifiedAtIv: file.encLastModifiedAt.iv, - isFavorite: file.isFavorite, - })); - }), - rename: roleProcedure["activeClient"] .input( z.object({ diff --git a/src/trpc/routers/upload.ts b/src/trpc/routers/upload.ts index 11b0a84..3b05cbb 100644 --- a/src/trpc/routers/upload.ts +++ b/src/trpc/routers/upload.ts @@ -173,7 +173,7 @@ const uploadRouter = router({ const { id, path } = await generateSessionId(); try { - await UploadRepo.createThumbnailOrMigrationUploadSession({ + await UploadRepo.createThumbnailUploadSession({ id, type: "thumbnail", userId: ctx.session.userId, @@ -251,112 +251,6 @@ const uploadRouter = router({ sessionLocks.delete(uploadId); } }), - - startMigrationUpload: roleProcedure["activeClient"] - .input( - z.object({ - file: z.int().positive(), - chunks: z.int().positive(), - dekVersion: z.date(), - }), - ) - .mutation(async ({ ctx, input }) => { - const { id, path } = await generateSessionId(); - - try { - await UploadRepo.createThumbnailOrMigrationUploadSession({ - id, - type: "migration", - userId: ctx.session.userId, - path, - totalChunks: input.chunks, - expiresAt: new Date(Date.now() + UPLOADS_EXPIRES), - fileId: input.file, - dekVersion: input.dekVersion, - }); - return { uploadId: id }; - } catch (e) { - await safeRecursiveRm(path); - - if (e instanceof IntegrityError) { - if (e.message === "File not found") { - throw new TRPCError({ code: "NOT_FOUND", message: "Invalid file id" }); - } else if (e.message === "File is not legacy") { - throw new TRPCError({ code: "BAD_REQUEST", message: e.message }); - } - } - throw e; - } - }), - - completeMigrationUpload: roleProcedure["activeClient"] - .input( - z.object({ - uploadId: z.uuidv4(), - }), - ) - .mutation(async ({ ctx, input }) => { - const { uploadId } = input; - if (sessionLocks.has(uploadId)) { - throw new TRPCError({ code: "CONFLICT", message: "Completion already in progress" }); - } else { - sessionLocks.add(uploadId); - } - - let filePath = ""; - - try { - const session = await UploadRepo.getUploadSession(uploadId, ctx.session.userId); - if (session?.type !== "migration") { - throw new TRPCError({ code: "NOT_FOUND", message: "Invalid upload id" }); - } else if (session.uploadedChunks < session.totalChunks) { - throw new TRPCError({ code: "BAD_REQUEST", message: "Upload not completed" }); - } - - filePath = `${env.libraryPath}/${ctx.session.userId}/${uuidv4()}`; - await mkdir(dirname(filePath), { recursive: true }); - - const hashStream = createHash("sha256"); - const writeStream = createWriteStream(filePath, { flags: "wx", mode: 0o600 }); - - for (let i = 1; i <= session.totalChunks; i++) { - for await (const chunk of createReadStream(`${session.path}/${i}`)) { - hashStream.update(chunk); - writeStream.write(chunk); - } - } - - await new Promise((resolve, reject) => { - writeStream.end((e: any) => (e ? reject(e) : resolve())); - }); - - const hash = hashStream.digest("base64"); - const oldPath = await db.transaction().execute(async (trx) => { - const { oldPath } = await FileRepo.migrateFileContent( - trx, - ctx.session.userId, - session.fileId, - filePath, - session.dekVersion!, - hash, - ); - await UploadRepo.deleteUploadSession(trx, uploadId); - return oldPath; - }); - - await Promise.all([safeUnlink(oldPath), safeRecursiveRm(session.path)]); - } catch (e) { - await safeUnlink(filePath); - - if (e instanceof IntegrityError && e.message === "File is not legacy") { - // File migrated after this upload started - throw new TRPCError({ code: "CONFLICT", message: e.message }); - } - throw e; - } finally { - sessionLocks.delete(uploadId); - } - }), }); export default uploadRouter;