mirror of
https://github.com/immich-app/immich.git
synced 2026-05-16 20:42:12 -04:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bee49cef02 | |||
| 6d0c6a4008 | |||
| 8a975e5ea9 | |||
| d39e7da10d | |||
| bc400d68ac | |||
| d7f038ec60 | |||
| 26957f37ce | |||
| 3254d31cd2 | |||
| 7b269d1638 | |||
| b5bed02300 | |||
| 5553910236 |
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/cli",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"description": "Command Line Interface (CLI) for Immich",
|
||||
"type": "module",
|
||||
"exports": "./dist/index.js",
|
||||
@@ -28,7 +28,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^63.0.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"prettier": "^3.7.4",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"paths": {
|
||||
"src/*": ["./src/*"],
|
||||
},
|
||||
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
|
||||
"types": ["vitest/globals"]
|
||||
},
|
||||
"exclude": ["dist", "node_modules", "vite.config.ts"]
|
||||
|
||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"label": "v2.7.2",
|
||||
"url": "https://docs.v2.7.2.archive.immich.app"
|
||||
"label": "v2.7.4",
|
||||
"url": "https://docs.v2.7.4.archive.immich.app"
|
||||
},
|
||||
{
|
||||
"label": "v2.6.3",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-e2e",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@@ -40,7 +40,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^63.0.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"exiftool-vendored": "^35.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"luxon": "^3.4.4",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-i18n",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"format": "prettier --cache --check .",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "immich-ml"
|
||||
version = "2.7.2"
|
||||
version = "2.7.4"
|
||||
description = ""
|
||||
authors = [{ name = "Hau Tran", email = "alex.tran1502@gmail.com" }]
|
||||
requires-python = ">=3.11,<4.0"
|
||||
|
||||
Generated
+1
-1
@@ -898,7 +898,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "immich-ml"
|
||||
version = "2.7.2"
|
||||
version = "2.7.4"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "aiocache" },
|
||||
|
||||
@@ -113,8 +113,8 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
|
||||
implementation 'org.chromium.net:cronet-embedded:143.7445.0'
|
||||
implementation("androidx.media3:media3-datasource-okhttp:1.9.2")
|
||||
implementation("androidx.media3:media3-datasource-cronet:1.9.2")
|
||||
implementation("androidx.media3:media3-datasource-okhttp:1.10.0")
|
||||
implementation("androidx.media3:media3-datasource-cronet:1.10.0")
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
|
||||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
implementation "androidx.concurrent:concurrent-futures:$concurrent_version"
|
||||
|
||||
@@ -35,8 +35,8 @@ platform :android do
|
||||
task: 'bundle',
|
||||
build_type: 'Release',
|
||||
properties: {
|
||||
"android.injected.version.code" => 3043,
|
||||
"android.injected.version.name" => "2.7.2",
|
||||
"android.injected.version.code" => 3045,
|
||||
"android.injected.version.name" => "2.7.4",
|
||||
}
|
||||
)
|
||||
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
import Foundation
|
||||
|
||||
class ImageRequest: @unchecked Sendable {
|
||||
private struct State: Sendable {
|
||||
var isCancelled = false
|
||||
}
|
||||
|
||||
let completion: @Sendable (Result<[String: Int64]?, any Error>) -> Void
|
||||
private let state: Mutex<State>
|
||||
|
||||
var isCancelled: Bool {
|
||||
get {
|
||||
state.withLock { $0.isCancelled }
|
||||
}
|
||||
set {
|
||||
state.withLock { $0.isCancelled = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
init(completion: @escaping @Sendable (Result<[String: Int64]?, any Error>) -> Void) {
|
||||
self.state = Mutex(State())
|
||||
self.completion = completion
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
isCancelled = true
|
||||
}
|
||||
}
|
||||
|
||||
struct RequestRegistry<T: AnyObject & Sendable>: ~Copyable, Sendable {
|
||||
private let requests = Mutex<[Int64: T]>([:])
|
||||
|
||||
|
||||
@@ -3,21 +3,6 @@ import Flutter
|
||||
import MobileCoreServices
|
||||
import Photos
|
||||
|
||||
class LocalImageRequest {
|
||||
weak var operation: Operation?
|
||||
var isCancelled = false
|
||||
let callback: (Result<[String: Int64]?, any Error>) -> Void
|
||||
|
||||
init(callback: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
|
||||
self.callback = callback
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
isCancelled = true
|
||||
operation?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
class LocalImageApiImpl: LocalImageApi {
|
||||
private static let imageManager = PHImageManager.default()
|
||||
private static let fetchOptions = {
|
||||
@@ -36,9 +21,9 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
return requestOptions
|
||||
}()
|
||||
|
||||
private static let registry = RequestRegistry<LocalImageRequest>()
|
||||
private static let registry = RequestRegistry<ImageRequest>()
|
||||
|
||||
private static var rgbaFormat = vImage_CGImageFormat(
|
||||
private static let rgbaFormat = vImage_CGImageFormat(
|
||||
bitsPerComponent: 8,
|
||||
bitsPerPixel: 32,
|
||||
colorSpace: CGColorSpaceCreateDeviceRGB(),
|
||||
@@ -67,21 +52,20 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
}
|
||||
|
||||
func requestImage(assetId: String, requestId: Int64, width: Int64, height: Int64, isVideo: Bool, preferEncoded: Bool, completion: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
|
||||
let request = LocalImageRequest(callback: completion)
|
||||
let request = ImageRequest(completion: completion)
|
||||
let operation = BlockOperation {
|
||||
if request.isCancelled {
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
guard let asset = Self.requestAsset(assetId: assetId)
|
||||
else {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
completion(.failure(PigeonError(code: "", message: "Could not get asset data for \(assetId)", details: nil)))
|
||||
return
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Could not get asset data for \(assetId)", details: nil)))
|
||||
}
|
||||
|
||||
if request.isCancelled {
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
if preferEncoded {
|
||||
@@ -100,12 +84,12 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
)
|
||||
|
||||
if request.isCancelled {
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
guard let data = imageData else {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return completion(.failure(PigeonError(code: "", message: "Could not get image data for \(assetId)", details: nil)))
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Could not get image data for \(assetId)", details: nil)))
|
||||
}
|
||||
|
||||
let length = data.count
|
||||
@@ -114,15 +98,14 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
|
||||
if request.isCancelled {
|
||||
free(pointer)
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
request.callback(.success([
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return request.completion(.success([
|
||||
"pointer": Int64(Int(bitPattern: pointer)),
|
||||
"length": Int64(length),
|
||||
]))
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return
|
||||
}
|
||||
|
||||
var image: UIImage?
|
||||
@@ -137,17 +120,17 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
)
|
||||
|
||||
if request.isCancelled {
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
guard let image = image,
|
||||
let cgImage = image.cgImage else {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return completion(.failure(PigeonError(code: "", message: "Could not get pixel data for \(assetId)", details: nil)))
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Could not get pixel data for \(assetId)", details: nil)))
|
||||
}
|
||||
|
||||
if request.isCancelled {
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -155,23 +138,22 @@ class LocalImageApiImpl: LocalImageApi {
|
||||
|
||||
if request.isCancelled {
|
||||
buffer.free()
|
||||
return completion(ImageProcessing.cancelledResult)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
request.callback(.success([
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return request.completion(.success([
|
||||
"pointer": Int64(Int(bitPattern: buffer.data)),
|
||||
"width": Int64(buffer.width),
|
||||
"height": Int64(buffer.height),
|
||||
"rowBytes": Int64(buffer.rowBytes),
|
||||
]))
|
||||
Self.registry.remove(requestId: requestId)
|
||||
} catch {
|
||||
Self.registry.remove(requestId: requestId)
|
||||
return completion(.failure(PigeonError(code: "", message: "Failed to convert image for \(assetId): \(error)", details: nil)))
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Failed to convert image for \(assetId): \(error)", details: nil)))
|
||||
}
|
||||
}
|
||||
|
||||
request.operation = operation
|
||||
Self.registry.add(requestId: requestId, request: request)
|
||||
ImageProcessing.queue.addOperation(operation)
|
||||
}
|
||||
|
||||
@@ -3,27 +3,24 @@ import Flutter
|
||||
import MobileCoreServices
|
||||
import Photos
|
||||
|
||||
class RemoteImageRequest {
|
||||
weak var task: URLSessionDataTask?
|
||||
final class RemoteImageRequest: ImageRequest {
|
||||
var task: URLSessionDataTask?
|
||||
let id: Int64
|
||||
var isCancelled = false
|
||||
let completion: (Result<[String: Int64]?, any Error>) -> Void
|
||||
|
||||
init(id: Int64, task: URLSessionDataTask, completion: @escaping (Result<[String: Int64]?, any Error>) -> Void) {
|
||||
init(id: Int64, completion: @escaping @Sendable (Result<[String: Int64]?, any Error>) -> Void) {
|
||||
self.id = id
|
||||
self.task = task
|
||||
self.completion = completion
|
||||
super.init(completion: completion)
|
||||
}
|
||||
|
||||
func cancel() {
|
||||
isCancelled = true
|
||||
override func cancel() {
|
||||
super.cancel()
|
||||
task?.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteImageApiImpl: NSObject, RemoteImageApi {
|
||||
private static let registry = RequestRegistry<RemoteImageRequest>()
|
||||
private static var rgbaFormat = vImage_CGImageFormat(
|
||||
private static let rgbaFormat = vImage_CGImageFormat(
|
||||
bitsPerComponent: 8,
|
||||
bitsPerPixel: 32,
|
||||
colorSpace: CGColorSpaceCreateDeviceRGB(),
|
||||
@@ -41,62 +38,58 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
|
||||
var urlRequest = URLRequest(url: URL(string: url)!)
|
||||
urlRequest.cachePolicy = .returnCacheDataElseLoad
|
||||
|
||||
let request = RemoteImageRequest(id: requestId, completion: completion)
|
||||
|
||||
let task = URLSessionManager.shared.session.dataTask(with: urlRequest) { data, response, error in
|
||||
Self.handleCompletion(requestId: requestId, encoded: preferEncoded, data: data, response: response, error: error)
|
||||
Self.handleCompletion(request: request, encoded: preferEncoded, data: data, response: response, error: error)
|
||||
}
|
||||
|
||||
let request = RemoteImageRequest(id: requestId, task: task, completion: completion)
|
||||
|
||||
request.task = task
|
||||
Self.registry.add(requestId: requestId, request: request)
|
||||
|
||||
task.resume()
|
||||
}
|
||||
|
||||
private static func handleCompletion(requestId: Int64, encoded: Bool, data: Data?, response: URLResponse?, error: Error?) {
|
||||
guard let request = registry.remove(requestId: requestId) else {
|
||||
return
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
if request.isCancelled || (error as NSError).code == NSURLErrorCancelled {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
return request.completion(.failure(error))
|
||||
}
|
||||
|
||||
private static func handleCompletion(request: RemoteImageRequest, encoded: Bool, data: Data?, response: URLResponse?, error: Error?) {
|
||||
if request.isCancelled {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
if let error = error {
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(.failure(error))
|
||||
}
|
||||
|
||||
guard let data = data else {
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(.failure(PigeonError(code: "", message: "No data received", details: nil)))
|
||||
}
|
||||
|
||||
if encoded {
|
||||
let length = data.count
|
||||
let pointer = malloc(length)!
|
||||
data.copyBytes(to: pointer.assumingMemoryBound(to: UInt8.self), count: length)
|
||||
|
||||
if request.isCancelled {
|
||||
free(pointer)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(
|
||||
.success([
|
||||
"pointer": Int64(Int(bitPattern: pointer)),
|
||||
"length": Int64(length),
|
||||
]))
|
||||
}
|
||||
|
||||
ImageProcessing.queue.addOperation {
|
||||
if request.isCancelled {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
// Return raw encoded bytes when requested (for animated images)
|
||||
if encoded {
|
||||
let length = data.count
|
||||
let pointer = malloc(length)!
|
||||
data.copyBytes(to: pointer.assumingMemoryBound(to: UInt8.self), count: length)
|
||||
|
||||
if request.isCancelled {
|
||||
free(pointer)
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
return request.completion(
|
||||
.success([
|
||||
"pointer": Int64(Int(bitPattern: pointer)),
|
||||
"length": Int64(length),
|
||||
]))
|
||||
}
|
||||
|
||||
guard let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
|
||||
let cgImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, decodeOptions) else {
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Failed to decode image for request", details: nil)))
|
||||
}
|
||||
|
||||
@@ -112,14 +105,16 @@ class RemoteImageApiImpl: NSObject, RemoteImageApi {
|
||||
return request.completion(ImageProcessing.cancelledResult)
|
||||
}
|
||||
|
||||
request.completion(
|
||||
.success([
|
||||
"pointer": Int64(Int(bitPattern: buffer.data)),
|
||||
"width": Int64(buffer.width),
|
||||
"height": Int64(buffer.height),
|
||||
"rowBytes": Int64(buffer.rowBytes),
|
||||
]))
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(
|
||||
.success([
|
||||
"pointer": Int64(Int(bitPattern: buffer.data)),
|
||||
"width": Int64(buffer.width),
|
||||
"height": Int64(buffer.height),
|
||||
"rowBytes": Int64(buffer.rowBytes),
|
||||
]))
|
||||
} catch {
|
||||
registry.remove(requestId: request.id)
|
||||
return request.completion(.failure(PigeonError(code: "", message: "Failed to convert image for request: \(error)", details: nil)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.7.2</string>
|
||||
<string>2.7.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -45,14 +45,17 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
|
||||
final backupNotifier = ref.read(driftBackupProvider.notifier);
|
||||
final syncManager = ref.read(backgroundSyncProvider);
|
||||
|
||||
ref.read(driftBackupProvider.notifier).updateSyncing(true);
|
||||
syncSuccess = await ref.read(backgroundSyncProvider).syncRemote();
|
||||
ref.read(driftBackupProvider.notifier).updateSyncing(false);
|
||||
await backupNotifier.getBackupStatus(currentUser.id);
|
||||
|
||||
backupNotifier.updateSyncing(true);
|
||||
syncSuccess = await syncManager.syncRemote();
|
||||
backupNotifier.updateSyncing(false);
|
||||
|
||||
if (mounted) {
|
||||
await ref.read(driftBackupProvider.notifier).getBackupStatus(currentUser.id);
|
||||
await backupNotifier.getBackupStatus(currentUser.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -82,9 +85,9 @@ class _DriftBackupPageState extends ConsumerState<DriftBackupPage> {
|
||||
}
|
||||
|
||||
if (syncSuccess == null) {
|
||||
ref.read(driftBackupProvider.notifier).updateSyncing(true);
|
||||
backupNotifier.updateSyncing(true);
|
||||
syncSuccess = await backupSyncManager.syncRemote();
|
||||
ref.read(driftBackupProvider.notifier).updateSyncing(false);
|
||||
backupNotifier.updateSyncing(false);
|
||||
}
|
||||
|
||||
await backupNotifier.getBackupStatus(currentUser.id);
|
||||
|
||||
@@ -51,7 +51,7 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
|
||||
return null;
|
||||
}
|
||||
|
||||
Stream<ImageInfo> loadRequest(ImageRequest request, ImageDecoderCallback decode, {bool evictOnError = true}) async* {
|
||||
Stream<ImageInfo> loadRequest(ImageRequest request, ImageDecoderCallback decode, {required bool isFinal}) async* {
|
||||
if (isCancelled) {
|
||||
this.request = null;
|
||||
return;
|
||||
@@ -59,21 +59,18 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
|
||||
|
||||
try {
|
||||
final image = await request.load(decode);
|
||||
if (isCancelled) {
|
||||
return;
|
||||
}
|
||||
if (image == null && evictOnError) {
|
||||
PaintingBinding.instance.imageCache.evict(this);
|
||||
return;
|
||||
} else if (image == null) {
|
||||
if (isCancelled || image == null) {
|
||||
image?.dispose();
|
||||
return;
|
||||
}
|
||||
isFinished = isFinal;
|
||||
yield image;
|
||||
} catch (e, stack) {
|
||||
if (isCancelled) {
|
||||
return;
|
||||
}
|
||||
if (evictOnError) {
|
||||
if (isFinal) {
|
||||
isFinished = true;
|
||||
PaintingBinding.instance.imageCache.evict(this);
|
||||
rethrow;
|
||||
}
|
||||
@@ -83,7 +80,7 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
|
||||
}
|
||||
}
|
||||
|
||||
Future<ui.Codec?> loadCodecRequest(ImageRequest request) async {
|
||||
Future<ui.Codec?> loadCodecRequest(ImageRequest request, {required bool isFinal}) async {
|
||||
if (isCancelled) {
|
||||
this.request = null;
|
||||
return null;
|
||||
@@ -91,20 +88,19 @@ mixin CancellableImageProviderMixin<T extends Object> on CancellableImageProvide
|
||||
|
||||
try {
|
||||
final codec = await request.loadCodec();
|
||||
if (isCancelled) {
|
||||
if (isCancelled || codec == null) {
|
||||
codec?.dispose();
|
||||
return null;
|
||||
}
|
||||
if (codec == null) {
|
||||
PaintingBinding.instance.imageCache.evict(this);
|
||||
return null;
|
||||
}
|
||||
isFinished = isFinal;
|
||||
return codec;
|
||||
} catch (e) {
|
||||
if (!isCancelled) {
|
||||
if (isFinal) {
|
||||
isFinished = true;
|
||||
PaintingBinding.instance.imageCache.evict(this);
|
||||
rethrow;
|
||||
}
|
||||
rethrow;
|
||||
return null;
|
||||
} finally {
|
||||
this.request = null;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class LocalThumbProvider extends CancellableImageProvider<LocalThumbProvider>
|
||||
|
||||
Stream<ImageInfo> _codec(LocalThumbProvider key, ImageDecoderCallback decode) {
|
||||
final request = this.request = LocalImageRequest(localId: key.id, size: key.size, assetType: key.assetType);
|
||||
return loadRequest(request, decode);
|
||||
return loadRequest(request, decode, isFinal: true);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -103,16 +103,16 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
|
||||
return;
|
||||
}
|
||||
|
||||
final loadOriginal = Store.get(StoreKey.loadOriginal, false);
|
||||
final devicePixelRatio = PlatformDispatcher.instance.views.first.devicePixelRatio;
|
||||
var request = this.request = LocalImageRequest(
|
||||
localId: key.id,
|
||||
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
|
||||
assetType: key.assetType,
|
||||
);
|
||||
yield* loadRequest(request, decode);
|
||||
yield* loadRequest(request, decode, isFinal: !loadOriginal);
|
||||
|
||||
if (!Store.get(StoreKey.loadOriginal, false)) {
|
||||
isFinished = true;
|
||||
if (!loadOriginal) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,8 +122,7 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
|
||||
|
||||
request = this.request = LocalImageRequest(localId: key.id, assetType: key.assetType, size: Size.zero);
|
||||
|
||||
yield* loadRequest(request, decode);
|
||||
isFinished = true;
|
||||
yield* loadRequest(request, decode, isFinal: true);
|
||||
}
|
||||
|
||||
Stream<Object> _animatedCodec(LocalFullImageProvider key, ImageDecoderCallback decode) async* {
|
||||
@@ -139,7 +138,7 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
|
||||
size: Size(size.width * devicePixelRatio, size.height * devicePixelRatio),
|
||||
assetType: key.assetType,
|
||||
);
|
||||
yield* loadRequest(previewRequest, decode);
|
||||
yield* loadRequest(previewRequest, decode, isFinal: false);
|
||||
|
||||
if (isCancelled) {
|
||||
return;
|
||||
@@ -147,13 +146,12 @@ class LocalFullImageProvider extends CancellableImageProvider<LocalFullImageProv
|
||||
|
||||
// always try original for animated, since previews don't support animation
|
||||
final originalRequest = request = LocalImageRequest(localId: key.id, size: Size.zero, assetType: key.assetType);
|
||||
final codec = await loadCodecRequest(originalRequest);
|
||||
final codec = await loadCodecRequest(originalRequest, isFinal: true);
|
||||
if (codec == null) {
|
||||
if (isCancelled) return;
|
||||
throw StateError('Failed to load animated codec for local asset ${key.id}');
|
||||
}
|
||||
yield codec;
|
||||
isFinished = true;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -38,7 +38,7 @@ class RemoteImageProvider extends CancellableImageProvider<RemoteImageProvider>
|
||||
|
||||
Stream<ImageInfo> _codec(RemoteImageProvider key, ImageDecoderCallback decode) {
|
||||
final request = this.request = RemoteImageRequest(uri: key.url);
|
||||
return loadRequest(request, decode);
|
||||
return loadRequest(request, decode, isFinal: true);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -112,10 +112,9 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
uri: getThumbnailUrlForRemoteId(key.assetId, type: AssetMediaSize.preview, thumbhash: key.thumbhash),
|
||||
);
|
||||
final loadOriginal = assetType == AssetType.image && AppSetting.get(Setting.loadOriginal);
|
||||
yield* loadRequest(previewRequest, decode, evictOnError: !loadOriginal);
|
||||
yield* loadRequest(previewRequest, decode, isFinal: !loadOriginal);
|
||||
|
||||
if (!loadOriginal) {
|
||||
isFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -124,8 +123,7 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
}
|
||||
|
||||
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId));
|
||||
yield* loadRequest(originalRequest, decode);
|
||||
isFinished = true;
|
||||
yield* loadRequest(originalRequest, decode, isFinal: true);
|
||||
}
|
||||
|
||||
Stream<Object> _animatedCodec(RemoteFullImageProvider key, ImageDecoderCallback decode) async* {
|
||||
@@ -138,7 +136,7 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
final previewRequest = request = RemoteImageRequest(
|
||||
uri: getThumbnailUrlForRemoteId(key.assetId, type: AssetMediaSize.preview, thumbhash: key.thumbhash),
|
||||
);
|
||||
yield* loadRequest(previewRequest, decode, evictOnError: false);
|
||||
yield* loadRequest(previewRequest, decode, isFinal: false);
|
||||
|
||||
if (isCancelled) {
|
||||
return;
|
||||
@@ -146,7 +144,7 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
|
||||
// always try original for animated, since previews don't support animation
|
||||
final originalRequest = request = RemoteImageRequest(uri: getOriginalUrlForRemoteId(key.assetId));
|
||||
final codec = await loadCodecRequest(originalRequest);
|
||||
final codec = await loadCodecRequest(originalRequest, isFinal: true);
|
||||
if (codec == null) {
|
||||
if (isCancelled) {
|
||||
return;
|
||||
@@ -154,7 +152,6 @@ class RemoteFullImageProvider extends CancellableImageProvider<RemoteFullImagePr
|
||||
throw StateError('Failed to load animated codec for asset ${key.assetId}');
|
||||
}
|
||||
yield codec;
|
||||
isFinished = true;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -22,7 +22,7 @@ class ThumbHashProvider extends CancellableImageProvider<ThumbHashProvider>
|
||||
|
||||
Stream<ImageInfo> _loadCodec(ThumbHashProvider key, ImageDecoderCallback decode) {
|
||||
final request = this.request = ThumbhashImageRequest(thumbhash: key.thumbHash);
|
||||
return loadRequest(request, decode);
|
||||
return loadRequest(request, decode, isFinal: true);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
Generated
+1
-1
@@ -3,7 +3,7 @@ Immich API
|
||||
|
||||
This Dart package is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
||||
|
||||
- API version: 2.7.2
|
||||
- API version: 2.7.4
|
||||
- Generator version: 7.8.0
|
||||
- Build package: org.openapitools.codegen.languages.DartClientCodegen
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ name: immich_mobile
|
||||
description: Immich - selfhosted backup media file on mobile phone
|
||||
|
||||
publish_to: 'none'
|
||||
version: 2.7.2+3043
|
||||
version: 2.7.4+3045
|
||||
|
||||
environment:
|
||||
sdk: '>=3.8.0 <4.0.0'
|
||||
|
||||
@@ -15225,7 +15225,7 @@
|
||||
"info": {
|
||||
"title": "Immich",
|
||||
"description": "Immich API",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@immich/sdk",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"description": "Auto-generated TypeScript SDK for the Immich API",
|
||||
"type": "module",
|
||||
"main": "./build/index.js",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Immich
|
||||
* 2.7.2
|
||||
* 2.7.4
|
||||
* DO NOT MODIFY - This file has been generated using oazapfts.
|
||||
* See https://www.npmjs.com/package/oazapfts
|
||||
*/
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-monorepo",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"description": "Monorepo for Immich",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@10.32.1+sha512.a706938f0e89ac1456b6563eab4edf1d1faf3368d1191fc5c59790e96dc918e4456ab2e67d613de1043d2e8c81f87303e6b40d4ffeca9df15ef1ad567348f2be",
|
||||
|
||||
Generated
+27
-241
@@ -87,8 +87,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^63.0.0
|
||||
version: 63.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
specifier: ^64.0.0
|
||||
version: 64.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
globals:
|
||||
specifier: ^17.0.0
|
||||
version: 17.4.0
|
||||
@@ -241,8 +241,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^63.0.0
|
||||
version: 63.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
specifier: ^64.0.0
|
||||
version: 64.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
exiftool-vendored:
|
||||
specifier: ^35.0.0
|
||||
version: 35.15.1
|
||||
@@ -278,7 +278,7 @@ importers:
|
||||
version: 6.0.2
|
||||
typescript-eslint:
|
||||
specifier: ^8.28.0
|
||||
version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
version: 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
utimes:
|
||||
specifier: ^5.2.1
|
||||
version: 5.2.1(encoding@0.1.13)
|
||||
@@ -553,9 +553,6 @@ importers:
|
||||
sanitize-filename:
|
||||
specifier: ^1.6.3
|
||||
version: 1.6.4
|
||||
sanitize-html:
|
||||
specifier: ^2.14.0
|
||||
version: 2.17.2
|
||||
semver:
|
||||
specifier: ^7.6.2
|
||||
version: 7.7.4
|
||||
@@ -659,9 +656,6 @@ importers:
|
||||
'@types/react':
|
||||
specifier: ^19.0.0
|
||||
version: 19.2.14
|
||||
'@types/sanitize-html':
|
||||
specifier: ^2.13.0
|
||||
version: 2.16.1
|
||||
'@types/semver':
|
||||
specifier: ^7.5.8
|
||||
version: 7.7.1
|
||||
@@ -687,8 +681,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@10.1.0(jiti@2.6.1)))(eslint@10.1.0(jiti@2.6.1))(prettier@3.8.1)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^63.0.0
|
||||
version: 63.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
specifier: ^64.0.0
|
||||
version: 64.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
globals:
|
||||
specifier: ^17.0.0
|
||||
version: 17.4.0
|
||||
@@ -724,7 +718,7 @@ importers:
|
||||
version: 6.0.2
|
||||
typescript-eslint:
|
||||
specifier: ^8.28.0
|
||||
version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
version: 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
unplugin-swc:
|
||||
specifier: ^1.4.5
|
||||
version: 1.5.9(@swc/core@1.15.18(@swc/helpers@0.5.17))(rollup@4.55.1)
|
||||
@@ -934,8 +928,8 @@ importers:
|
||||
specifier: ^3.12.4
|
||||
version: 3.16.0(eslint@10.1.0(jiti@2.6.1))(svelte@5.54.1)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^63.0.0
|
||||
version: 63.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
specifier: ^64.0.0
|
||||
version: 64.0.0(eslint@10.1.0(jiti@2.6.1))
|
||||
factory.ts:
|
||||
specifier: ^1.4.1
|
||||
version: 1.4.2
|
||||
@@ -974,7 +968,7 @@ importers:
|
||||
version: 6.0.2
|
||||
typescript-eslint:
|
||||
specifier: ^8.45.0
|
||||
version: 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
version: 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
vite:
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.4)(jiti@2.6.1)(sass@1.97.1)(terser@5.44.1)(tsx@4.21.0)(yaml@2.8.3)
|
||||
@@ -5167,9 +5161,6 @@ packages:
|
||||
'@types/retry@0.12.2':
|
||||
resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==}
|
||||
|
||||
'@types/sanitize-html@2.16.1':
|
||||
resolution: {integrity: sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==}
|
||||
|
||||
'@types/sax@1.2.7':
|
||||
resolution: {integrity: sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==}
|
||||
|
||||
@@ -5242,14 +5233,6 @@ packages:
|
||||
'@types/yargs@17.0.35':
|
||||
resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.57.1':
|
||||
resolution: {integrity: sha512-Gn3aqnvNl4NGc6x3/Bqk1AOn0thyTU9bqDRhiRnUWezgvr2OnhYCWCgC8zXXRVqBsIL1pSDt7T9nJUe0oM0kDQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.57.1
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.58.0':
|
||||
resolution: {integrity: sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -5258,13 +5241,6 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/parser@8.57.1':
|
||||
resolution: {integrity: sha512-k4eNDan0EIMTT/dUKc/g+rsJ6wcHYhNPdY19VoX/EOtaAG8DLtKCykhrUnuHPYvinn5jhAPgD2Qw9hXBwrahsw==}
|
||||
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/parser@8.58.0':
|
||||
resolution: {integrity: sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -5272,45 +5248,22 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.57.1':
|
||||
resolution: {integrity: sha512-vx1F37BRO1OftsYlmG9xay1TqnjNVlqALymwWVuYTdo18XuKxtBpCj1QlzNIEHlvlB27osvXFWptYiEWsVdYsg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/project-service@8.58.0':
|
||||
resolution: {integrity: sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/scope-manager@8.57.1':
|
||||
resolution: {integrity: sha512-hs/QcpCwlwT2L5S+3fT6gp0PabyGk4Q0Rv2doJXA0435/OpnSR3VRgvrp8Xdoc3UAYSg9cyUjTeFXZEPg/3OKg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/scope-manager@8.58.0':
|
||||
resolution: {integrity: sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.57.1':
|
||||
resolution: {integrity: sha512-0lgOZB8cl19fHO4eI46YUx2EceQqhgkPSuCGLlGi79L2jwYY1cxeYc1Nae8Aw1xjgW3PKVDLlr3YJ6Bxx8HkWg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.58.0':
|
||||
resolution: {integrity: sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/type-utils@8.57.1':
|
||||
resolution: {integrity: sha512-+Bwwm0ScukFdyoJsh2u6pp4S9ktegF98pYUU0hkphOOqdMB+1sNQhIz8y5E9+4pOioZijrkfNO/HUJVAFFfPKA==}
|
||||
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/type-utils@8.58.0':
|
||||
resolution: {integrity: sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -5318,33 +5271,16 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/types@8.57.1':
|
||||
resolution: {integrity: sha512-S29BOBPJSFUiblEl6RzPPjJt6w25A6XsBqRVDt53tA/tlL8q7ceQNZHTjPeONt/3S7KRI4quk+yP9jK2WjBiPQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/types@8.58.0':
|
||||
resolution: {integrity: sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.57.1':
|
||||
resolution: {integrity: sha512-ybe2hS9G6pXpqGtPli9Gx9quNV0TWLOmh58ADlmZe9DguLq0tiAKVjirSbtM1szG6+QH6rVXyU6GTLQbWnMY+g==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.0.0'
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.58.0':
|
||||
resolution: {integrity: sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/utils@8.57.1':
|
||||
resolution: {integrity: sha512-XUNSJ/lEVFttPMMoDVA2r2bwrl8/oPx8cURtczkSEswY5T3AeLmCy+EKWQNdL4u0MmAHOjcWrqJp2cdvgjn8dQ==}
|
||||
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/utils@8.58.0':
|
||||
resolution: {integrity: sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -5352,10 +5288,6 @@ packages:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
typescript: '>=4.8.4 <6.1.0'
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.57.1':
|
||||
resolution: {integrity: sha512-YWnmJkXbofiz9KbnbbwuA2rpGkFPLbAIetcCNO6mJ8gdhdZ/v7WDXsoGFAJuM6ikUFKTlSQnjWnVO4ux+UzS6A==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.58.0':
|
||||
resolution: {integrity: sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -6138,8 +6070,8 @@ packages:
|
||||
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
ci-info@4.3.1:
|
||||
resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==}
|
||||
ci-info@4.4.0:
|
||||
resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
citty@0.1.6:
|
||||
@@ -6420,8 +6352,8 @@ packages:
|
||||
peerDependencies:
|
||||
webpack: ^5.1.0
|
||||
|
||||
core-js-compat@3.47.0:
|
||||
resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==}
|
||||
core-js-compat@3.49.0:
|
||||
resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==}
|
||||
|
||||
core-js-pure@3.47.0:
|
||||
resolution: {integrity: sha512-BcxeDbzUrRnXGYIVAGFtcGQVNpFcUhVjr6W7F8XktvQW2iJP9e66GP6xdKotCRFlrxBvNIBrhwKteRXqMV86Nw==}
|
||||
@@ -7244,8 +7176,8 @@ packages:
|
||||
svelte:
|
||||
optional: true
|
||||
|
||||
eslint-plugin-unicorn@63.0.0:
|
||||
resolution: {integrity: sha512-Iqecl9118uQEXYh7adylgEmGfkn5es3/mlQTLLkd4pXkIk9CTGrAbeUux+YljSa2ohXCBmQQ0+Ej1kZaFgcfkA==}
|
||||
eslint-plugin-unicorn@64.0.0:
|
||||
resolution: {integrity: sha512-rNZwalHh8i0UfPlhNwg5BTUO1CMdKNmjqe+TgzOTZnpKoi8VBgsW7u9qCHIdpxEzZ1uwrJrPF0uRb7l//K38gA==}
|
||||
engines: {node: ^20.10.0 || >=21.0.0}
|
||||
peerDependencies:
|
||||
eslint: '>=9.38.0'
|
||||
@@ -7971,9 +7903,6 @@ packages:
|
||||
webpack:
|
||||
optional: true
|
||||
|
||||
htmlparser2@10.1.0:
|
||||
resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==}
|
||||
|
||||
htmlparser2@6.1.0:
|
||||
resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
|
||||
|
||||
@@ -8303,10 +8232,6 @@ packages:
|
||||
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-plain-object@5.0.0:
|
||||
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-potential-custom-element-name@1.0.1:
|
||||
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
|
||||
|
||||
@@ -9692,9 +9617,6 @@ packages:
|
||||
parse-numeric-range@1.3.0:
|
||||
resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==}
|
||||
|
||||
parse-srcset@1.0.2:
|
||||
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==}
|
||||
|
||||
@@ -10892,9 +10814,6 @@ packages:
|
||||
sanitize-filename@1.6.4:
|
||||
resolution: {integrity: sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==}
|
||||
|
||||
sanitize-html@2.17.2:
|
||||
resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==}
|
||||
|
||||
sass@1.97.1:
|
||||
resolution: {integrity: sha512-uf6HoO8fy6ClsrShvMgaKUn14f2EHQLQRtpsZZLeU/Mv0Q1K5P0+x2uvH6Cub39TVVbWNSrraUhDAoFph6vh0A==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -11777,13 +11696,6 @@ packages:
|
||||
typedarray@0.0.6:
|
||||
resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==}
|
||||
|
||||
typescript-eslint@8.57.1:
|
||||
resolution: {integrity: sha512-fLvZWf+cAGw3tqMCYzGIU6yR8K+Y9NT2z23RwOjlNFF2HwSB3KhdEFI5lSBv8tNmFkkBShSjsCjzx1vahZfISA==}
|
||||
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@8.58.0:
|
||||
resolution: {integrity: sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -13460,7 +13372,7 @@ snapshots:
|
||||
babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5)
|
||||
babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5)
|
||||
babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5)
|
||||
core-js-compat: 3.47.0
|
||||
core-js-compat: 3.49.0
|
||||
semver: 6.3.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -15512,8 +15424,8 @@ snapshots:
|
||||
'@koddsson/eslint-plugin-tscompat@0.2.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@mdn/browser-compat-data': 6.1.5
|
||||
'@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/type-utils': 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/utils': 8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
browserslist: 4.28.1
|
||||
transitivePeerDependencies:
|
||||
- eslint
|
||||
@@ -17459,10 +17371,6 @@ snapshots:
|
||||
|
||||
'@types/retry@0.12.2': {}
|
||||
|
||||
'@types/sanitize-html@2.16.1':
|
||||
dependencies:
|
||||
htmlparser2: 10.1.0
|
||||
|
||||
'@types/sax@1.2.7':
|
||||
dependencies:
|
||||
'@types/node': 24.12.2
|
||||
@@ -17552,22 +17460,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/yargs-parser': 21.0.3
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/scope-manager': 8.57.1
|
||||
'@typescript-eslint/type-utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/visitor-keys': 8.57.1
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
ignore: 7.0.5
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.5.0(typescript@6.0.2)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
@@ -17584,18 +17476,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.57.1
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
'@typescript-eslint/typescript-estree': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/visitor-keys': 8.57.1
|
||||
debug: 4.4.3
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.58.0
|
||||
@@ -17608,15 +17488,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.57.1(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
debug: 4.4.3
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/project-service@8.58.0(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/tsconfig-utils': 8.58.0(typescript@6.0.2)
|
||||
@@ -17626,36 +17497,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@8.57.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
'@typescript-eslint/visitor-keys': 8.57.1
|
||||
|
||||
'@typescript-eslint/scope-manager@8.58.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.58.0
|
||||
'@typescript-eslint/visitor-keys': 8.58.0
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.57.1(typescript@6.0.2)':
|
||||
dependencies:
|
||||
typescript: 6.0.2
|
||||
|
||||
'@typescript-eslint/tsconfig-utils@8.58.0(typescript@6.0.2)':
|
||||
dependencies:
|
||||
typescript: 6.0.2
|
||||
|
||||
'@typescript-eslint/type-utils@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
'@typescript-eslint/typescript-estree': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
debug: 4.4.3
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
ts-api-utils: 2.5.0(typescript@6.0.2)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/type-utils@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.58.0
|
||||
@@ -17668,25 +17518,8 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@8.57.1': {}
|
||||
|
||||
'@typescript-eslint/types@8.58.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.57.1(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/tsconfig-utils': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
'@typescript-eslint/visitor-keys': 8.57.1
|
||||
debug: 4.4.3
|
||||
minimatch: 10.2.4
|
||||
semver: 7.7.4
|
||||
tinyglobby: 0.2.15
|
||||
ts-api-utils: 2.5.0(typescript@6.0.2)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.58.0(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/project-service': 8.58.0(typescript@6.0.2)
|
||||
@@ -17702,17 +17535,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1))
|
||||
'@typescript-eslint/scope-manager': 8.57.1
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
'@typescript-eslint/typescript-estree': 8.57.1(typescript@6.0.2)
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1))
|
||||
@@ -17724,11 +17546,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.57.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.57.1
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.58.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.58.0
|
||||
@@ -18249,7 +18066,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@babel/core': 7.28.5
|
||||
'@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5)
|
||||
core-js-compat: 3.47.0
|
||||
core-js-compat: 3.49.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -18664,7 +18481,7 @@ snapshots:
|
||||
|
||||
ci-info@3.9.0: {}
|
||||
|
||||
ci-info@4.3.1: {}
|
||||
ci-info@4.4.0: {}
|
||||
|
||||
citty@0.1.6:
|
||||
dependencies:
|
||||
@@ -18916,7 +18733,7 @@ snapshots:
|
||||
serialize-javascript: 6.0.2
|
||||
webpack: 5.104.1
|
||||
|
||||
core-js-compat@3.47.0:
|
||||
core-js-compat@3.49.0:
|
||||
dependencies:
|
||||
browserslist: 4.28.1
|
||||
|
||||
@@ -19870,17 +19687,17 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
eslint-plugin-unicorn@63.0.0(eslint@10.1.0(jiti@2.6.1)):
|
||||
eslint-plugin-unicorn@64.0.0(eslint@10.1.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1))
|
||||
change-case: 5.4.4
|
||||
ci-info: 4.3.1
|
||||
ci-info: 4.4.0
|
||||
clean-regexp: 1.0.0
|
||||
core-js-compat: 3.47.0
|
||||
core-js-compat: 3.49.0
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
find-up-simple: 1.0.1
|
||||
globals: 16.5.0
|
||||
globals: 17.4.0
|
||||
indent-string: 5.0.0
|
||||
is-builtin-module: 5.0.0
|
||||
jsesc: 3.1.0
|
||||
@@ -20865,13 +20682,6 @@ snapshots:
|
||||
optionalDependencies:
|
||||
webpack: 5.104.1
|
||||
|
||||
htmlparser2@10.1.0:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.2.2
|
||||
entities: 7.0.1
|
||||
|
||||
htmlparser2@6.1.0:
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
@@ -21200,8 +21010,6 @@ snapshots:
|
||||
dependencies:
|
||||
isobject: 3.0.1
|
||||
|
||||
is-plain-object@5.0.0: {}
|
||||
|
||||
is-potential-custom-element-name@1.0.1:
|
||||
optional: true
|
||||
|
||||
@@ -22933,8 +22741,6 @@ snapshots:
|
||||
|
||||
parse-numeric-range@1.3.0: {}
|
||||
|
||||
parse-srcset@1.0.2: {}
|
||||
|
||||
parse5-htmlparser2-tree-adapter@7.1.0:
|
||||
dependencies:
|
||||
domhandler: 5.0.3
|
||||
@@ -24278,15 +24084,6 @@ snapshots:
|
||||
dependencies:
|
||||
truncate-utf8-bytes: 1.0.2
|
||||
|
||||
sanitize-html@2.17.2:
|
||||
dependencies:
|
||||
deepmerge: 4.3.1
|
||||
escape-string-regexp: 4.0.0
|
||||
htmlparser2: 10.1.0
|
||||
is-plain-object: 5.0.0
|
||||
parse-srcset: 1.0.2
|
||||
postcss: 8.5.8
|
||||
|
||||
sass@1.97.1:
|
||||
dependencies:
|
||||
chokidar: 4.0.3
|
||||
@@ -25404,17 +25201,6 @@ snapshots:
|
||||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typescript-eslint@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.57.1(@typescript-eslint/parser@8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/parser': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
'@typescript-eslint/typescript-estree': 8.57.1(typescript@6.0.2)
|
||||
'@typescript-eslint/utils': 8.57.1(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
typescript: 6.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
typescript-eslint@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.58.0(@typescript-eslint/parser@8.58.0(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2))(eslint@10.1.0(jiti@2.6.1))(typescript@6.0.2)
|
||||
|
||||
+2
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"description": "",
|
||||
"author": "",
|
||||
"private": true,
|
||||
@@ -110,7 +110,6 @@
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"sanitize-html": "^2.14.0",
|
||||
"semver": "^7.6.2",
|
||||
"sharp": "^0.34.5",
|
||||
"sirv": "^3.0.0",
|
||||
@@ -147,7 +146,6 @@
|
||||
"@types/picomatch": "^4.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/react": "^19.0.0",
|
||||
"@types/sanitize-html": "^2.13.0",
|
||||
"@types/semver": "^7.5.8",
|
||||
"@types/supertest": "^7.0.0",
|
||||
"@types/ua-parser-js": "^0.7.36",
|
||||
@@ -156,7 +154,7 @@
|
||||
"eslint": "^10.0.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-unicorn": "^63.0.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"globals": "^17.0.0",
|
||||
"mock-fs": "^5.2.0",
|
||||
"node-gyp": "^12.0.0",
|
||||
|
||||
@@ -58,6 +58,7 @@ export class OcrRepository {
|
||||
})
|
||||
upsert(assetId: string, ocrDataList: Insertable<AssetOcrTable>[], searchText: string) {
|
||||
let query = this.db.with('deleted_ocr', (db) => db.deleteFrom('asset_ocr').where('assetId', '=', assetId));
|
||||
// eslint-disable-next-line unicorn/prefer-ternary
|
||||
if (ocrDataList.length > 0) {
|
||||
(query as any) = query
|
||||
.with('inserted_ocr', (db) => db.insertInto('asset_ocr').values(ocrDataList))
|
||||
|
||||
@@ -265,11 +265,13 @@ export class AlbumService extends BaseService {
|
||||
}
|
||||
|
||||
async removeAssets(auth: AuthDto, id: string, dto: BulkIdsDto): Promise<BulkIdResponseDto[]> {
|
||||
await this.requireAccess({ auth, permission: Permission.AlbumAssetDelete, ids: [id] });
|
||||
|
||||
const album = await this.findOrFail(id, { withAssets: false });
|
||||
const results = await removeAssets(
|
||||
auth,
|
||||
{ access: this.accessRepository, bulk: this.albumRepository },
|
||||
{ parentId: id, assetIds: dto.ids, canAlwaysRemove: Permission.AlbumUpdate },
|
||||
{ parentId: id, assetIds: dto.ids, canAlwaysRemove: Permission.AlbumDelete },
|
||||
);
|
||||
|
||||
const removedIds = results.filter(({ success }) => success).map(({ id }) => id);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { ApiService, render } from 'src/services/api.service';
|
||||
|
||||
describe(ApiService.name, () => {
|
||||
describe('render', () => {
|
||||
it('should correctly render open graph tags', () => {
|
||||
const output = render('<!-- metadata:tags -->', {
|
||||
title: 'title',
|
||||
description: 'description',
|
||||
imageUrl: 'https://demo.immich.app/api/assets/123',
|
||||
});
|
||||
expect(output).toContain('<meta property="og:title" content="title" />');
|
||||
expect(output).toContain('<meta property="og:description" content="description" />');
|
||||
expect(output).toContain('<meta property="og:image" content="https://demo.immich.app/api/assets/123" />');
|
||||
});
|
||||
|
||||
it('should escape html tags', () => {
|
||||
expect(
|
||||
render('<!-- metadata:tags -->', {
|
||||
title: "<script>console.log('hello')</script>Test",
|
||||
description: 'description',
|
||||
}),
|
||||
).toContain(
|
||||
'<meta property="og:title" content="<script>console.log('hello')</script>Test" />',
|
||||
);
|
||||
});
|
||||
|
||||
it('should escape quotes', () => {
|
||||
expect(
|
||||
render('<!-- metadata:tags -->', {
|
||||
title: `0;url=https://example.com" http-equiv="refresh`,
|
||||
description: 'description',
|
||||
}),
|
||||
).toContain('<meta property="og:title" content="0;url=https://example.com" http-equiv="refresh" />');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable, NotAcceptableException } from '@nestjs/common';
|
||||
import { NextFunction, Request, Response } from 'express';
|
||||
import { escape } from 'lodash';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { AuthService } from 'src/services/auth.service';
|
||||
@@ -10,7 +10,7 @@ import { OpenGraphTags } from 'src/utils/misc';
|
||||
|
||||
export const render = (index: string, meta: OpenGraphTags) => {
|
||||
const [title, description, imageUrl] = [meta.title, meta.description, meta.imageUrl].map((item) =>
|
||||
item ? sanitizeHtml(item, { allowedTags: [] }) : '',
|
||||
item ? escape(item) : '',
|
||||
);
|
||||
|
||||
const tags = `
|
||||
|
||||
@@ -692,6 +692,24 @@ describe(AssetMediaService.name, () => {
|
||||
);
|
||||
expect(mocks.asset.getForThumbnail).toHaveBeenCalledWith(asset.id, AssetFileType.Thumbnail, true);
|
||||
});
|
||||
|
||||
it('should not include original filename if requested using a shared link with showExif false', async () => {
|
||||
const asset = AssetFactory.from().file({ type: AssetFileType.Preview }).build();
|
||||
|
||||
mocks.access.asset.checkSharedLinkAccess.mockResolvedValue(new Set([asset.id]));
|
||||
mocks.asset.getForThumbnail.mockResolvedValue({ ...asset, path: asset.files[0].path });
|
||||
|
||||
const auth = AuthFactory.from().sharedLink({ showExif: false }).build();
|
||||
|
||||
await expect(sut.viewThumbnail(auth, asset.id, { size: AssetMediaSize.PREVIEW })).resolves.toEqual(
|
||||
new ImmichFileResponse({
|
||||
path: asset.files[0].path,
|
||||
cacheControl: CacheControl.PrivateWithCache,
|
||||
contentType: 'image/jpeg',
|
||||
fileName: `${asset.id}_preview.jpg`,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('playbackVideo', () => {
|
||||
|
||||
@@ -257,7 +257,9 @@ export class AssetMediaService extends BaseService {
|
||||
throw new NotFoundException('Asset media not found');
|
||||
}
|
||||
|
||||
const fileName = `${getFileNameWithoutExtension(originalFileName)}_${size}${getFilenameExtension(path)}`;
|
||||
const fileNameBase =
|
||||
auth.sharedLink && !auth.sharedLink.showExif ? id : getFileNameWithoutExtension(originalFileName);
|
||||
const fileName = `${fileNameBase}_${size}${getFilenameExtension(path)}`;
|
||||
|
||||
return new ImmichFileResponse({
|
||||
fileName,
|
||||
|
||||
@@ -223,6 +223,16 @@ const checkOtherAccess = async (access: AccessRepository, request: OtherAccessRe
|
||||
return setUnion(isOwner, isShared);
|
||||
}
|
||||
|
||||
case Permission.AlbumAssetDelete: {
|
||||
const isOwner = await access.album.checkOwnerAccess(auth.user.id, ids);
|
||||
const isShared = await access.album.checkSharedAlbumAccess(
|
||||
auth.user.id,
|
||||
setDifference(ids, isOwner),
|
||||
AlbumUserRole.Editor,
|
||||
);
|
||||
return setUnion(isOwner, isShared);
|
||||
}
|
||||
|
||||
case Permission.AssetUpload: {
|
||||
return ids.has(auth.user.id) ? new Set([auth.user.id]) : new Set<string>();
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"tsBuildInfoFile": "./dist/tsconfig.build.tsbuildinfo",
|
||||
},
|
||||
"exclude": ["dist", "node_modules", "upload", "test", "e2e", "**/*spec.ts"]
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"rootDir": ".",
|
||||
"jsx": "react",
|
||||
"types": ["vitest/globals"],
|
||||
"tsBuildInfoFile": "./dist/tsconfig.tsbuildinfo",
|
||||
"noErrorTruncation": true
|
||||
},
|
||||
"exclude": ["dist", "node_modules", "upload"]
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "immich-web",
|
||||
"version": "2.7.2",
|
||||
"version": "2.7.4",
|
||||
"license": "GNU Affero General Public License version 3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
@@ -91,7 +91,7 @@
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-compat": "^7.0.0",
|
||||
"eslint-plugin-svelte": "^3.12.4",
|
||||
"eslint-plugin-unicorn": "^63.0.0",
|
||||
"eslint-plugin-unicorn": "^64.0.0",
|
||||
"factory.ts": "^1.4.1",
|
||||
"globals": "^17.0.0",
|
||||
"happy-dom": "^20.0.0",
|
||||
|
||||
@@ -70,7 +70,12 @@
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
if (!force && searchedPeople.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) {
|
||||
if (
|
||||
!force &&
|
||||
searchedPeople.length > 0 &&
|
||||
searchedPeople.length < maximumLengthSearchPeople &&
|
||||
searchName.startsWith(searchWord)
|
||||
) {
|
||||
search();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user