fix: remove use of union types in response for now

This commit is contained in:
diced
2026-03-03 21:30:59 -08:00
parent ef6e0e00a0
commit ec7024242f
8 changed files with 180 additions and 103 deletions

View File

@@ -89,7 +89,7 @@
"swr": "^2.3.7",
"typescript-eslint": "^8.48.1",
"vite": "^7.2.7",
"zod": "^4.1.13",
"zod": "^4.3.6",
"zustand": "^5.0.9"
},
"devDependencies": {

88
pnpm-lock.yaml generated
View File

@@ -145,7 +145,7 @@ importers:
version: 5.1.0
fastify-type-provider-zod:
specifier: ^6.1.0
version: 6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.1.13)
version: 6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.3.6)
fluent-ffmpeg:
specifier: ^2.1.3
version: 2.1.3
@@ -210,8 +210,8 @@ importers:
specifier: ^7.2.7
version: 7.2.7(@types/node@24.10.1)(jiti@2.5.1)(sass@1.94.2)(sugarss@5.0.1(postcss@8.5.6))(tsx@4.21.0)(yaml@2.8.2)
zod:
specifier: ^4.1.13
version: 4.1.13
specifier: ^4.3.6
version: 4.3.6
zustand:
specifier: ^5.0.9
version: 5.0.9(@types/react@19.2.7)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1))
@@ -1123,89 +1123,105 @@ packages:
resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-arm@1.2.4':
resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-ppc64@1.2.4':
resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-riscv64@1.2.4':
resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-s390x@1.2.4':
resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linux-x64@1.2.4':
resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-libvips-linuxmusl-arm64@1.2.4':
resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-libvips-linuxmusl-x64@1.2.4':
resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-linux-arm64@0.34.5':
resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-arm@0.34.5':
resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm]
os: [linux]
libc: [glibc]
'@img/sharp-linux-ppc64@0.34.5':
resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-riscv64@0.34.5':
resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@img/sharp-linux-s390x@0.34.5':
resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@img/sharp-linux-x64@0.34.5':
resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [glibc]
'@img/sharp-linuxmusl-arm64@0.34.5':
resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [arm64]
os: [linux]
libc: [musl]
'@img/sharp-linuxmusl-x64@0.34.5':
resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==}
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
cpu: [x64]
os: [linux]
libc: [musl]
'@img/sharp-wasm32@0.34.5':
resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==}
@@ -1393,36 +1409,42 @@ packages:
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm-musl@2.5.1':
resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==}
engines: {node: '>= 10.0.0'}
cpu: [arm]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-arm64-glibc@2.5.1':
resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-arm64-musl@2.5.1':
resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==}
engines: {node: '>= 10.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@parcel/watcher-linux-x64-glibc@2.5.1':
resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@parcel/watcher-linux-x64-musl@2.5.1':
resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==}
engines: {node: '>= 10.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
'@parcel/watcher-win32-arm64@2.5.1':
resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==}
@@ -1617,56 +1639,67 @@ packages:
resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
cpu: [arm]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm-musleabihf@4.53.3':
resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
cpu: [arm]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-arm64-gnu@4.53.3':
resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-arm64-musl@4.53.3':
resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
cpu: [arm64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-loong64-gnu@4.53.3':
resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
cpu: [loong64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-ppc64-gnu@4.53.3':
resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
cpu: [ppc64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-gnu@4.53.3':
resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-riscv64-musl@4.53.3':
resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
cpu: [riscv64]
os: [linux]
libc: [musl]
'@rollup/rollup-linux-s390x-gnu@4.53.3':
resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
cpu: [s390x]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-gnu@4.53.3':
resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
cpu: [x64]
os: [linux]
libc: [glibc]
'@rollup/rollup-linux-x64-musl@4.53.3':
resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
cpu: [x64]
os: [linux]
libc: [musl]
'@rollup/rollup-openharmony-arm64@4.53.3':
resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
@@ -2004,8 +2037,8 @@ packages:
'@types/d3-scale@4.0.9':
resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
'@types/d3-shape@3.1.7':
resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==}
'@types/d3-shape@3.1.8':
resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==}
'@types/d3-time@3.0.4':
resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
@@ -2607,8 +2640,8 @@ packages:
resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
engines: {node: '>=12'}
d3-format@3.1.0:
resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
d3-format@3.1.2:
resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
engines: {node: '>=12'}
d3-interpolate@3.0.1:
@@ -2978,8 +3011,8 @@ packages:
fast-diff@1.3.0:
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
fast-equals@5.3.3:
resolution: {integrity: sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==}
fast-equals@5.4.0:
resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==}
engines: {node: '>=6.0.0'}
fast-fifo@1.3.2:
@@ -3597,6 +3630,9 @@ packages:
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
lodash@4.17.23:
resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==}
longest-streak@3.1.0:
resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==}
@@ -5206,8 +5242,8 @@ packages:
peerDependencies:
zod: ^3.25.0 || ^4.0.0
zod@4.1.13:
resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==}
zod@4.3.6:
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
zustand@5.0.9:
resolution: {integrity: sha512-ALBtUj0AfjJt3uNRQoL1tL2tMvj6Gp/6e39dnfT6uzpelGru8v1tPOGBzayOWbPJvujM8JojDk3E1LxeFisBNg==}
@@ -7392,7 +7428,7 @@ snapshots:
dependencies:
'@types/d3-time': 3.0.4
'@types/d3-shape@3.1.7':
'@types/d3-shape@3.1.8':
dependencies:
'@types/d3-path': 3.1.1
@@ -8039,7 +8075,7 @@ snapshots:
d3-ease@3.0.1: {}
d3-format@3.1.0: {}
d3-format@3.1.2: {}
d3-interpolate@3.0.1:
dependencies:
@@ -8050,7 +8086,7 @@ snapshots:
d3-scale@4.0.2:
dependencies:
d3-array: 3.2.4
d3-format: 3.1.0
d3-format: 3.1.2
d3-interpolate: 3.0.1
d3-time: 3.1.0
d3-time-format: 4.1.0
@@ -8402,8 +8438,8 @@ snapshots:
'@babel/parser': 7.28.5
eslint: 9.39.1(jiti@2.5.1)
hermes-parser: 0.25.1
zod: 4.1.13
zod-validation-error: 4.0.2(zod@4.1.13)
zod: 4.3.6
zod-validation-error: 4.0.2(zod@4.3.6)
transitivePeerDependencies:
- supports-color
@@ -8535,7 +8571,7 @@ snapshots:
fast-diff@1.3.0: {}
fast-equals@5.3.3: {}
fast-equals@5.4.0: {}
fast-fifo@1.3.2: {}
@@ -8572,13 +8608,13 @@ snapshots:
fastify-plugin@5.1.0: {}
fastify-type-provider-zod@6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.1.13):
fastify-type-provider-zod@6.1.0(@fastify/swagger@9.6.1)(fastify@5.6.2)(openapi-types@12.1.3)(zod@4.3.6):
dependencies:
'@fastify/error': 4.2.0
'@fastify/swagger': 9.6.1
fastify: 5.6.2
openapi-types: 12.1.3
zod: 4.1.13
zod: 4.3.6
fastify@5.6.2:
dependencies:
@@ -9222,6 +9258,8 @@ snapshots:
lodash@4.17.21: {}
lodash@4.17.23: {}
longest-streak@3.1.0: {}
loose-envify@1.4.0:
@@ -10134,7 +10172,7 @@ snapshots:
react-smooth@4.0.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies:
fast-equals: 5.3.3
fast-equals: 5.4.0
prop-types: 15.8.1
react: 19.2.1
react-dom: 19.2.1(react@19.2.1)
@@ -10233,7 +10271,7 @@ snapshots:
dependencies:
clsx: 2.1.1
eventemitter3: 4.0.7
lodash: 4.17.21
lodash: 4.17.23
react: 19.2.1
react-dom: 19.2.1(react@19.2.1)
react-is: 18.3.1
@@ -11026,7 +11064,7 @@ snapshots:
'@types/d3-ease': 3.0.2
'@types/d3-interpolate': 3.0.4
'@types/d3-scale': 4.0.9
'@types/d3-shape': 3.1.7
'@types/d3-shape': 3.1.8
'@types/d3-time': 3.0.4
'@types/d3-timer': 3.0.2
d3-array: 3.2.4
@@ -11183,11 +11221,11 @@ snapshots:
compress-commons: 6.0.2
readable-stream: 4.7.0
zod-validation-error@4.0.2(zod@4.1.13):
zod-validation-error@4.0.2(zod@4.3.6):
dependencies:
zod: 4.1.13
zod: 4.3.6
zod@4.1.13: {}
zod@4.3.6: {}
zustand@5.0.9(@types/react@19.2.7)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)):
optionalDependencies:

View File

@@ -61,11 +61,11 @@ export const export4Schema = z.object({
id: z.string(),
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
username: z.string(),
password: z.string().nullable().optional(),
avatar: z.string().nullable().optional(),
password: z.string().nullish(),
avatar: z.string().nullish(),
role: z.enum(Role),
view: z.record(z.string(), z.unknown()),
totpSecret: z.string().nullable().optional(),
view: z.record(z.string(), z.any()),
totpSecret: z.string().nullish(),
}),
),
userPasskeys: z.array(
@@ -74,11 +74,10 @@ export const export4Schema = z.object({
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
lastUsed: z
.string()
.nullable()
.optional()
.nullish()
.refine((date) => (date ? !isNaN(Date.parse(date)) : true), 'Invalid date'),
name: z.string(),
reg: z.record(z.string(), z.unknown()),
reg: z.record(z.string(), z.any()),
userId: z.string(),
}),
),
@@ -87,10 +86,10 @@ export const export4Schema = z.object({
id: z.string(),
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
filesQuota: z.enum(UserFilesQuota),
maxBytes: z.string().nullable().optional(),
maxFiles: z.number().nullable().optional(),
maxUrls: z.number().nullable().optional(),
userId: z.string().nullable().optional(),
maxBytes: z.string().nullish(),
maxFiles: z.number().nullish(),
maxUrls: z.number().nullish(),
userId: z.string().nullish(),
}),
),
userOauthProviders: z.array(
@@ -100,8 +99,8 @@ export const export4Schema = z.object({
provider: z.enum(OAuthProviderType),
username: z.string(),
accessToken: z.string(),
refreshToken: z.string().nullable().optional(),
oauthId: z.string().nullable().optional(),
refreshToken: z.string().nullish(),
oauthId: z.string().nullish(),
userId: z.string(),
}),
),
@@ -110,7 +109,7 @@ export const export4Schema = z.object({
id: z.string(),
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
name: z.string(),
color: z.string().nullable().optional(),
color: z.string().nullish(),
files: z.array(z.string()),
userId: z.string(),
}),
@@ -121,12 +120,11 @@ export const export4Schema = z.object({
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
expiresAt: z
.string()
.nullable()
.optional()
.nullish()
.refine((date) => (date ? !isNaN(Date.parse(date)) : true), 'Invalid date'),
code: z.string(),
uses: z.number(),
maxUses: z.number().nullable().optional(),
maxUses: z.number().nullish(),
inviterId: z.string(),
}),
),
@@ -139,7 +137,7 @@ export const export4Schema = z.object({
allowUploads: z.boolean(),
files: z.array(z.string()),
userId: z.string(),
parentId: z.string().nullable().optional(),
parentId: z.string().nullish(),
}),
),
urls: z.array(
@@ -147,13 +145,13 @@ export const export4Schema = z.object({
id: z.string(),
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
code: z.string(),
vanity: z.string().nullable().optional(),
vanity: z.string().nullish(),
destination: z.string(),
views: z.number(),
maxViews: z.number().nullable().optional(),
password: z.string().nullable().optional(),
maxViews: z.number().nullish(),
password: z.string().nullish(),
enabled: z.boolean(),
userId: z.string().nullable().optional(),
userId: z.string().nullish(),
}),
),
files: z.array(
@@ -162,19 +160,18 @@ export const export4Schema = z.object({
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
deletesAt: z
.string()
.nullable()
.optional()
.nullish()
.refine((date) => (date ? !isNaN(Date.parse(date)) : true), 'Invalid date'),
name: z.string(),
originalName: z.string().nullable().optional(),
originalName: z.string().nullish(),
size: z.number(),
type: z.string(),
views: z.number(),
maxViews: z.number().nullable().optional(),
maxViews: z.number().nullish(),
favorite: z.boolean(),
password: z.string().nullable().optional(),
password: z.string().nullish(),
userId: z.string().nullable(),
folderId: z.string().nullable().optional(),
folderId: z.string().nullish(),
}),
),
thumbnails: z.array(
@@ -189,7 +186,7 @@ export const export4Schema = z.object({
z.object({
id: z.string(),
createdAt: z.string().refine((date) => !isNaN(Date.parse(date)), 'Invalid date'),
data: z.record(z.string(), z.unknown()),
data: z.record(z.string(), z.any()),
}),
),
}),

View File

@@ -1,3 +1,4 @@
import { ApiError } from '@/lib/api/errors';
import { bytes } from '@/lib/bytes';
import { reloadSettings } from '@/lib/config';
import { checkDbVars, REQUIRED_DB_VARS } from '@/lib/config/read/env';
@@ -7,6 +8,7 @@ import { runMigrations } from '@/lib/db/migration';
import { log } from '@/lib/logger';
import { isAdministrator } from '@/lib/role';
import { Tasks } from '@/lib/tasks';
import cleanThumbnails from '@/lib/tasks/run/cleanThumbnails';
import clearInvites from '@/lib/tasks/run/clearInvites';
import deleteFiles from '@/lib/tasks/run/deleteFiles';
import maxViews from '@/lib/tasks/run/maxViews';
@@ -22,6 +24,7 @@ import fastifySwagger from '@fastify/swagger';
import fastify from 'fastify';
import {
hasZodFastifySchemaValidationErrors,
isResponseSerializationError,
jsonSchemaTransform,
serializerCompiler,
validatorCompiler,
@@ -36,8 +39,6 @@ import vitePlugin from './plugins/vite';
import loadRoutes from './routes';
import { filesRoute } from './routes/files.dy';
import { urlsRoute } from './routes/urls.dy';
import cleanThumbnails from '@/lib/tasks/run/cleanThumbnails';
import { API_ERRORS, ApiError } from '@/lib/api/errors';
const MODE = process.env.NODE_ENV || 'production';
const logger = log('server');
@@ -242,13 +243,24 @@ async function main() {
server.setErrorHandler((error: any, _, res) => {
if (hasZodFastifySchemaValidationErrors(error)) {
return res.status(400).send({
error: error.message ?? '1000: Invalid response schema',
error: error.message ?? 'E1000: Invalid response schema',
statusCode: 400,
code: API_ERRORS[1000],
code: 1000,
issues: error.validation,
});
}
if (isResponseSerializationError(error)) {
console.log(error);
return res.status(500).send({
error: 'E1000: Response serialization error',
statusCode: 500,
code: 1000,
details: error.message,
});
}
if (error instanceof ApiError) {
const apiError = error as ApiError;
return res.status(apiError.status).send(apiError.toJSON());
@@ -259,7 +271,11 @@ async function main() {
} else {
console.error(error);
return res.status(500).send({ error: 'Internal Server Error', statusCode: 500 });
return res.status(500).send({
code: 9000,
error: 'E9000: Internal Server Error',
statusCode: 500,
});
}
});

View File

@@ -1,10 +1,11 @@
import { ApiError } from '@/lib/api/errors';
import { Export4, export4Schema } from '@/lib/import/version4/validateExport';
import { Export4 } from '@/lib/import/version4/validateExport';
import { log } from '@/lib/logger';
import { administratorMiddleware } from '@/server/middleware/administrator';
import { userMiddleware } from '@/server/middleware/user';
import { prisma } from '@/lib/db';
import { zQsBoolean } from '@/lib/validation';
import typedPlugin from '@/server/typedPlugin';
import { cpus, hostname, platform, release } from 'os';
import z from 'zod';
@@ -56,20 +57,23 @@ export default typedPlugin(
description:
'Export Zipline server data as a version 4 export bundle or return aggregate counts of core resources.',
querystring: z.object({
nometrics: z.string().optional(),
counts: z.string().optional(),
nometrics: zQsBoolean.optional(),
counts: zQsBoolean.optional(),
}),
response: {
200: z.union([
exportCountsSchema.describe('if ?counts=true'),
export4Schema.describe('if ?counts is not true or not there'),
// TODO: fix later
// exportCountsSchema.describe('if ?counts=true'),
// export4Schema.describe('if ?counts is not true or not there'),
z.any().describe('if ?counts=true'),
z.any().describe('if ?counts is not true or not there'),
]),
},
},
preHandler: [userMiddleware, administratorMiddleware],
},
async (req, res) => {
if (req.query.counts === 'true') {
if (req.query.counts) {
const counts = await getCounts();
return res.send(counts);
@@ -162,7 +166,7 @@ export default typedPlugin(
id: passkey.id,
lastUsed: passkey.lastUsed ? passkey.lastUsed.toISOString() : null,
name: passkey.name,
reg: passkey.reg as Record<string, unknown>,
reg: passkey.reg as Record<string, any>,
userId: passkey.userId,
});
}
@@ -294,9 +298,9 @@ export default typedPlugin(
}
return res
.header('Content-Disposition', `attachment; filename*=utf-8''zipline4_export_${Date.now()}.json`)
.header('Content-Disposition', `attachment; filename='zipline4_export_${Date.now()}.json'`)
.type('application/json')
.send(export4);
.send(export4 satisfies Export4);
},
);
},

View File

@@ -1,7 +1,7 @@
import { ApiError } from '@/lib/api/errors';
import { checkQuota, getDomain, getExtension, getFilename, getMimetype } from '@/lib/api/upload';
import { bytes } from '@/lib/bytes';
import { COMPRESS_TYPES, compressFile, CompressResult } from '@/lib/compress';
import { compressFile, CompressResult } from '@/lib/compress';
import { config } from '@/lib/config';
import { hashPassword } from '@/lib/crypto';
import { datasource } from '@/lib/datasource';
@@ -54,29 +54,37 @@ export default typedPlugin(
consumes: ['multipart/form-data'],
response: {
200: z.union([
z.string().describe('if the noJson option is true, returns a comma-separated list of URLs'),
z.object({
files: z.array(
z.object({
id: z.string(),
name: z.string(),
type: z.string(),
url: z.string(),
pending: z.boolean().optional(),
removedGps: z.boolean().optional(),
compressed: z
.object({
mimetype: z.string(),
ext: z.enum(COMPRESS_TYPES),
failed: z.boolean().optional(),
})
.optional(),
}),
z.any().describe('if the noJson option is true, returns a comma-separated list of URLs'),
z
.any()
.describe(
'if the noJson option is not true or not there, returns a JSON object with file details',
),
deletesAt: z.string().optional(),
assumedMimetypes: z.array(z.boolean()).optional(),
}),
]),
// 200: z.union([
// z.string().describe('if the noJson option is true, returns a comma-separated list of URLs'),
// z.object({
// files: z.array(
// z.object({
// id: z.string(),
// name: z.string(),
// type: z.string(),
// url: z.string(),
// pending: z.boolean().optional(),
// removedGps: z.boolean().optional(),
// compressed: z
// .object({
// mimetype: z.string(),
// ext: z.enum(COMPRESS_TYPES),
// failed: z.boolean().optional(),
// })
// .optional(),
// }),
// ),
// deletesAt: z.string().optional(),
// assumedMimetypes: z.array(z.boolean()).optional(),
// }),
// ]),
},
},
},

View File

@@ -270,15 +270,19 @@ export default typedPlugin(
params: paramsSchema,
response: {
200: z.union([
folderSchema
.partial()
.describe('if deleting a file from the folder, returns the updated folder'),
z
.object({
success: z.boolean(),
})
.describe('if deleting the folder, returns success status'),
z.any().describe('if deleting a file from the folder, returns the updated folder'),
z.any().describe('if deleting the folder, return success status'),
]),
// 200: z.union([
// folderSchema
// .partial()
// .describe('if deleting a file from the folder, returns the updated folder'),
// z
// .object({
// success: z.boolean(),
// })
// .describe('if deleting the folder, return success status'),
// ]),
},
},
preHandler: [userMiddleware, folderExistsAndEditable],

View File

@@ -47,11 +47,21 @@ export default typedPlugin(
'x-zipline-password': z.string().optional(),
}),
response: {
// 200: z.union([
// z.string(),
// urlSchema.omit({ password: true }).extend({
// url: z.string(),
// }),
// ]),
200: z.union([
z.string(),
urlSchema.omit({ password: true }).extend({
url: z.string(),
}),
z
.any()
.describe('if the x-zipline-no-json header is true, returns the shortened URL as plain text'),
z
.any()
.describe(
'if the x-zipline-no-json header is not true or not there, returns a JSON object with URL details',
),
]),
},
},