Merge remote-tracking branch 'origin/main' into feature/sync_assets_trashed_state

# Conflicts:
#	mobile/ios/Podfile.lock
This commit is contained in:
Peter Ombodi 2025-10-08 19:07:11 +03:00
commit 4d88ffe694
36 changed files with 451 additions and 296 deletions

View file

@ -73,7 +73,7 @@ jobs:
- name: Restore Gradle Cache
id: cache-gradle-restore
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
~/.gradle/caches
@ -130,7 +130,7 @@ jobs:
- name: Save Gradle Cache
id: cache-gradle-save
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
if: github.ref == 'refs/heads/main'
with:
path: |

View file

@ -20,7 +20,7 @@
"@types/lodash-es": "^4.17.12",
"@types/micromatch": "^4.0.9",
"@types/mock-fs": "^4.13.1",
"@types/node": "^22.18.1",
"@types/node": "^22.18.8",
"@vitest/coverage-v8": "^3.0.0",
"byte-size": "^9.0.0",
"cli-progress": "^3.12.0",

View file

@ -25,7 +25,7 @@
"@playwright/test": "^1.44.1",
"@socket.io/component-emitter": "^3.1.2",
"@types/luxon": "^3.4.2",
"@types/node": "^22.18.1",
"@types/node": "^22.18.8",
"@types/oidc-provider": "^9.0.0",
"@types/pg": "^8.15.1",
"@types/pngjs": "^6.0.4",

View file

@ -13,8 +13,16 @@ else:
module_dir = Path(__file__).parent
def is_ipv6(host: str) -> bool:
try:
return ip_address(host).version == 6
except ValueError:
return False
bind_host = non_prefixed_settings.immich_host
if ip_address(bind_host).version == 6:
if is_ipv6(bind_host):
bind_host = f"[{bind_host}]"
bind_address = f"{bind_host}:{non_prefixed_settings.immich_port}"

View file

@ -7,8 +7,16 @@ import requests
port = os.getenv("IMMICH_PORT", 3003)
host = os.getenv("IMMICH_HOST", "0.0.0.0")
def is_ipv6(host: str) -> bool:
try:
return ip_address(host).version == 6
except ValueError:
return False
host = "localhost" if host == "0.0.0.0" else host
host = f"[{host}]" if ip_address(host).version == 6 else host
host = f"[{host}]" if is_ipv6(host) else host
try:
response = requests.get(f"http://{host}:{port}/ping", timeout=2)

View file

@ -64,7 +64,7 @@ PODS:
- Flutter
- integration_test (0.0.1):
- Flutter
- isar_flutter_libs (1.0.0):
- isar_community_flutter_libs (1.0.0):
- Flutter
- local_auth_darwin (0.0.1):
- Flutter
@ -149,7 +149,7 @@ DEPENDENCIES:
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`)
- isar_community_flutter_libs (from `.symlinks/plugins/isar_community_flutter_libs/ios`)
- local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`)
- maplibre_gl (from `.symlinks/plugins/maplibre_gl/ios`)
- native_video_player (from `.symlinks/plugins/native_video_player/ios`)
@ -210,8 +210,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_picker_ios/ios"
integration_test:
:path: ".symlinks/plugins/integration_test/ios"
isar_flutter_libs:
:path: ".symlinks/plugins/isar_flutter_libs/ios"
isar_community_flutter_libs:
:path: ".symlinks/plugins/isar_community_flutter_libs/ios"
local_auth_darwin:
:path: ".symlinks/plugins/local_auth_darwin/darwin"
maplibre_gl:
@ -246,46 +246,46 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/wakelock_plus/ios"
SPEC CHECKSUMS:
background_downloader: a05c77d32a0d70615b9c04577aa203535fc924ff
bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
background_downloader: 50e91d979067b82081aba359d7d916b3ba5fadad
bonsoir_darwin: 29c7ccf356646118844721f36e1de4b61f6cbd0e
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab
flutter_web_auth_2: 06d500582775790a0d4c323222fcb6d7990f9603
fluttertoast: 21eecd6935e7064cc1fcb733a4c5a428f3f24f0f
geolocator_apple: 9bcea1918ff7f0062d98345d238ae12718acfbc1
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
isar_flutter_libs: fdf730ca925d05687f36d7f1d355e482529ed097
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13
flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
flutter_web_auth_2: 5c8d9dcd7848b5a9efb086d24e7a9adcae979c80
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
geolocator_apple: 1560c3c875af2a412242c7a923e15d0d401966ff
home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
isar_community_flutter_libs: bede843185a61a05ff364a05c9b23209523f7e0d
local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391
MapLibre: 69e572367f4ef6287e18246cfafc39c80cdcabcd
maplibre_gl: 753f55d763a81cbdba087d02af02d12206e6f94e
native_video_player: d12af78a1a4a8cf09775a5177d5b392def6fd23c
network_info_plus: 6613d9d7cdeb0e6f366ed4dbe4b3c51c52d567a9
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
photo_manager: ff695c7a1dd5bc379974953a2b5c0a293f7c4c8a
maplibre_gl: 3c924e44725147b03dda33430ad216005b40555f
native_video_player: b65c58951ede2f93d103a25366bdebca95081265
network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
photo_manager: d2fbcc0f2d82458700ee6256a15018210a81d413
SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
share_handler_ios: 6dd3a4ac5ca0d955274aec712ba0ecdcaf583e7c
share_handler_ios: e2244e990f826b2c8eaa291ac3831569438ba0fb
share_handler_ios_models: fc638c9b4330dc7f082586c92aee9dfa0b87b871
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
sqlite3: fc1400008a9b3525f5914ed715a5d1af0b8f4983
sqlite3_flutter_libs: cc304edcb8e1d8c595d1b08c7aeb46a47691d9db
sqlite3_flutter_libs: f8fc13346870e73fe35ebf6dbb997fbcd156b241
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
PODFILE CHECKSUM: 7ce312f2beab01395db96f6969d90a447279cf45

View file

@ -3,27 +3,30 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
class SearchResult {
final List<BaseAsset> assets;
final double scrollOffset;
final int? nextPage;
const SearchResult({required this.assets, this.nextPage});
const SearchResult({required this.assets, this.scrollOffset = 0.0, this.nextPage});
int get totalAssets => assets.length;
SearchResult copyWith({List<BaseAsset>? assets, int? nextPage}) {
return SearchResult(assets: assets ?? this.assets, nextPage: nextPage ?? this.nextPage);
SearchResult copyWith({List<BaseAsset>? assets, int? nextPage, double? scrollOffset}) {
return SearchResult(
assets: assets ?? this.assets,
nextPage: nextPage ?? this.nextPage,
scrollOffset: scrollOffset ?? this.scrollOffset,
);
}
@override
String toString() => 'SearchResult(assets: $assets, nextPage: $nextPage)';
String toString() => 'SearchResult(assets: ${assets.length}, nextPage: $nextPage, scrollOffset: $scrollOffset)';
@override
bool operator ==(covariant SearchResult other) {
if (identical(this, other)) return true;
final listEquals = const DeepCollectionEquality().equals;
return listEquals(other.assets, assets) && other.nextPage == nextPage;
return listEquals(other.assets, assets) && other.nextPage == nextPage && other.scrollOffset == scrollOffset;
}
@override
int get hashCode => assets.hashCode ^ nextPage.hashCode;
int get hashCode => assets.hashCode ^ nextPage.hashCode ^ scrollOffset.hashCode;
}

View file

@ -203,7 +203,7 @@ class TimelineService {
Future<void> dispose() async {
await _bucketSubscription?.cancel();
_bucketSubscription = null;
_buffer.clear();
_buffer = [];
_bufferOffset = 0;
}
}

View file

@ -132,7 +132,7 @@ const AlbumSchema = CollectionSchema(
getId: _albumGetId,
getLinks: _albumGetLinks,
attach: _albumAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _albumEstimateSize(

View file

@ -47,7 +47,7 @@ const AndroidDeviceAssetSchema = CollectionSchema(
getId: _androidDeviceAssetGetId,
getLinks: _androidDeviceAssetGetLinks,
attach: _androidDeviceAssetAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _androidDeviceAssetEstimateSize(

View file

@ -168,7 +168,7 @@ const AssetSchema = CollectionSchema(
getId: _assetGetId,
getLinks: _assetGetLinks,
attach: _assetAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _assetEstimateSize(

View file

@ -43,7 +43,7 @@ const BackupAlbumSchema = CollectionSchema(
getId: _backupAlbumGetId,
getLinks: _backupAlbumGetLinks,
attach: _backupAlbumAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _backupAlbumEstimateSize(

View file

@ -32,7 +32,7 @@ const DuplicatedAssetSchema = CollectionSchema(
getId: _duplicatedAssetGetId,
getLinks: _duplicatedAssetGetLinks,
attach: _duplicatedAssetAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _duplicatedAssetEstimateSize(

View file

@ -52,7 +52,7 @@ const ETagSchema = CollectionSchema(
getId: _eTagGetId,
getLinks: _eTagGetLinks,
attach: _eTagAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _eTagEstimateSize(

View file

@ -60,7 +60,7 @@ const IOSDeviceAssetSchema = CollectionSchema(
getId: _iOSDeviceAssetGetId,
getLinks: _iOSDeviceAssetGetLinks,
attach: _iOSDeviceAssetAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _iOSDeviceAssetEstimateSize(

View file

@ -65,7 +65,7 @@ const DeviceAssetEntitySchema = CollectionSchema(
getId: _deviceAssetEntityGetId,
getLinks: _deviceAssetEntityGetLinks,
attach: _deviceAssetEntityAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _deviceAssetEntityEstimateSize(

View file

@ -68,7 +68,7 @@ const ExifInfoSchema = CollectionSchema(
getId: _exifInfoGetId,
getLinks: _exifInfoGetLinks,
attach: _exifInfoAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _exifInfoEstimateSize(

View file

@ -37,7 +37,7 @@ const StoreValueSchema = CollectionSchema(
getId: _storeValueGetId,
getLinks: _storeValueGetLinks,
attach: _storeValueAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _storeValueEstimateSize(

View file

@ -95,7 +95,7 @@ const UserSchema = CollectionSchema(
getId: _userGetId,
getLinks: _userGetLinks,
attach: _userAttach,
version: '3.1.8',
version: '3.3.0-dev.3',
);
int _userEstimateSize(

View file

@ -599,9 +599,9 @@ class _SearchResultGrid extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final searchResult = ref.watch(paginatedSearchProvider);
final assets = ref.watch(paginatedSearchProvider.select((s) => s.assets));
if (searchResult.totalAssets == 0) {
if (assets.isEmpty) {
return const _SearchEmptyContent();
}
@ -615,6 +615,7 @@ class _SearchResultGrid extends ConsumerWidget {
if (metrics.pixels >= metrics.maxScrollExtent && isVerticalScroll && !isBottomSheetNotification) {
onScrollEnd();
ref.read(paginatedSearchProvider.notifier).setScrollOffset(metrics.maxScrollExtent);
}
return true;
@ -623,17 +624,18 @@ class _SearchResultGrid extends ConsumerWidget {
child: ProviderScope(
overrides: [
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(searchResult.assets);
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(assets);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
key: ValueKey(searchResult.totalAssets),
key: ValueKey(assets.length),
groupBy: GroupAssetsBy.none,
appBar: null,
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
snapToMonth: false,
initialScrollOffset: ref.read(paginatedSearchProvider.select((s) => s.scrollOffset)),
),
),
),

View file

@ -24,12 +24,20 @@ class PaginatedSearchNotifier extends StateNotifier<SearchResult> {
return false;
}
state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage);
state = SearchResult(
assets: [...state.assets, ...result.assets],
nextPage: result.nextPage,
scrollOffset: state.scrollOffset,
);
return true;
}
void setScrollOffset(double offset) {
state = state.copyWith(scrollOffset: offset);
}
clear() {
state = const SearchResult(assets: [], nextPage: 1);
state = const SearchResult(assets: [], nextPage: 1, scrollOffset: 0.0);
}
}

View file

@ -51,7 +51,7 @@ class AssetDetailBottomSheet extends ConsumerWidget {
isArchived: isArchived,
isTrashEnabled: isTrashEnable,
isInLockedView: isInLockedView,
isStacked: asset.hasRemote && (asset as RemoteAsset).stackId != null,
isStacked: asset is RemoteAsset && asset.stackId != null,
currentAlbum: currentAlbum,
advancedTroubleshooting: advancedTroubleshooting,
source: ActionSource.viewer,

View file

@ -322,6 +322,9 @@ class NativeVideoViewer extends HookConsumerWidget {
removeListeners(playerController);
}
if (value != null) {
isVisible.value = _isCurrentAsset(value, asset);
}
final curAsset = currentAsset.value;
if (curAsset == asset) {
return;

View file

@ -40,6 +40,7 @@ class Timeline extends StatelessWidget {
this.groupBy,
this.withScrubber = true,
this.snapToMonth = true,
this.initialScrollOffset,
});
final Widget? topSliverWidget;
@ -51,6 +52,7 @@ class Timeline extends StatelessWidget {
final GroupAssetsBy? groupBy;
final bool withScrubber;
final bool snapToMonth;
final double? initialScrollOffset;
@override
Widget build(BuildContext context) {
@ -78,6 +80,7 @@ class Timeline extends StatelessWidget {
bottomSheet: bottomSheet,
withScrubber: withScrubber,
snapToMonth: snapToMonth,
initialScrollOffset: initialScrollOffset,
),
),
),
@ -93,6 +96,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
this.bottomSheet,
this.withScrubber = true,
this.snapToMonth = true,
this.initialScrollOffset,
});
final Widget? topSliverWidget;
@ -101,6 +105,7 @@ class _SliverTimeline extends ConsumerStatefulWidget {
final Widget? bottomSheet;
final bool withScrubber;
final bool snapToMonth;
final double? initialScrollOffset;
@override
ConsumerState createState() => _SliverTimelineState();
@ -124,7 +129,10 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
@override
void initState() {
super.initState();
_scrollController = ScrollController(onAttach: _restoreScalePosition);
_scrollController = ScrollController(
initialScrollOffset: widget.initialScrollOffset ?? 0.0,
onAttach: _restoreScalePosition,
);
_eventSubscription = EventStream.shared.listen(_onEvent);
final currentTilesPerRow = ref.read(settingsProvider).get(Setting.tilesPerRow);

View file

@ -77,11 +77,14 @@ class ActionNotifier extends Notifier<void> {
return _getAssets(source).whereType<RemoteAsset>().toIds().toList(growable: false);
}
List<String> _getLocalIdsForSource(ActionSource source) {
List<String> _getLocalIdsForSource(ActionSource source, {bool ignoreLocalOnly = false}) {
final Set<BaseAsset> assets = _getAssets(source);
final List<String> localIds = [];
for (final asset in assets) {
if (ignoreLocalOnly && asset.storage != AssetState.merged) {
continue;
}
if (asset is LocalAsset) {
localIds.add(asset.id);
} else if (asset is RemoteAsset && asset.localId != null) {
@ -189,7 +192,7 @@ class ActionNotifier extends Notifier<void> {
Future<ActionResult> moveToLockFolder(ActionSource source) async {
final ids = _getOwnedRemoteIdsForSource(source);
final localIds = _getLocalIdsForSource(source);
final localIds = _getLocalIdsForSource(source, ignoreLocalOnly: true);
try {
await _service.moveToLockFolder(ids, localIds);
return ActionResult(count: ids.length, success: true);

View file

@ -1,5 +1,6 @@
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
@ -25,7 +26,28 @@ class AssetMediaRepository {
const AssetMediaRepository(this._assetApiRepository);
Future<List<String>> deleteAll(List<String> ids) => PhotoManager.editor.deleteWithIds(ids);
Future<bool> _androidSupportsTrash() async {
if (Platform.isAndroid) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
int sdkVersion = androidInfo.version.sdkInt;
return sdkVersion >= 31;
}
return false;
}
Future<List<String>> deleteAll(List<String> ids) async {
if (CurrentPlatform.isAndroid) {
if (await _androidSupportsTrash()) {
return PhotoManager.editor.android.moveToTrash(
ids.map((e) => AssetEntity(id: e, width: 1, height: 1, typeInt: 0)).toList(),
);
} else {
return PhotoManager.editor.deleteWithIds(ids);
}
}
return PhotoManager.editor.deleteWithIds(ids);
}
Future<asset_entity.Asset?> get(String id) async {
final entity = await AssetEntity.fromId(id);

View file

@ -317,10 +317,10 @@ packages:
dependency: "direct main"
description:
name: connectivity_plus
sha256: "04bf81bb0b77de31557b58d052b24b3eee33f09a6e7a8c68a3e247c7df19ec27"
sha256: b5e72753cf63becce2c61fd04dfe0f1c430cc5278b53a1342dc5ad839eab29ec
url: "https://pub.dev"
source: hosted
version: "6.1.3"
version: "6.1.5"
connectivity_plus_platform_interface:
dependency: transitive
description:
@ -1022,25 +1022,34 @@ packages:
isar:
dependency: "direct main"
description:
name: isar
sha256: e17a9555bc7f22ff26568b8c64d019b4ffa2dc6bd4cb1c8d9b269aefd32e53ad
url: "https://pub.isar-community.dev"
source: hosted
path: "packages/isar"
ref: bb1dca40fe87a001122e5d43bc6254718cb49f3a
resolved-ref: bb1dca40fe87a001122e5d43bc6254718cb49f3a
url: "https://github.com/immich-app/isar"
source: git
version: "3.1.8"
isar_flutter_libs:
isar_community:
dependency: transitive
description:
name: isar_community
sha256: "28f59e54636c45ba0bb1b3b7f2656f1c50325f740cea6efcd101900be3fba546"
url: "https://pub.dev"
source: hosted
version: "3.3.0-dev.3"
isar_community_flutter_libs:
dependency: "direct main"
description:
name: isar_flutter_libs
sha256: "78710781e658ce4bff59b3f38c5b2735e899e627f4e926e1221934e77b95231a"
url: "https://pub.isar-community.dev"
name: isar_community_flutter_libs
sha256: c2934fe755bb3181cb67602fd5df0d080b3d3eb52799f98623aa4fc5acbea010
url: "https://pub.dev"
source: hosted
version: "3.1.8"
version: "3.3.0-dev.3"
isar_generator:
dependency: "direct dev"
description:
path: "packages/isar_generator"
ref: v3
resolved-ref: ad574f60ed6f39d2995cd16fc7dc3de9a646ef30
ref: bb1dca40fe87a001122e5d43bc6254718cb49f3a
resolved-ref: bb1dca40fe87a001122e5d43bc6254718cb49f3a
url: "https://github.com/immich-app/isar"
source: git
version: "3.1.8"

View file

@ -8,8 +8,6 @@ environment:
sdk: '>=3.8.0 <4.0.0'
flutter: 3.35.4
isar_version: &isar_version 3.1.8
dependencies:
flutter:
sdk: flutter
@ -81,11 +79,11 @@ dependencies:
openapi:
path: openapi
isar:
version: *isar_version
hosted: https://pub.isar-community.dev/
isar_flutter_libs: # contains Isar Core
version: *isar_version
hosted: https://pub.isar-community.dev/
git:
url: https://github.com/immich-app/isar
ref: 'bb1dca40fe87a001122e5d43bc6254718cb49f3a'
path: packages/isar/
isar_community_flutter_libs: 3.3.0-dev.3
# DB
drift: ^2.23.1
drift_flutter: ^0.2.4
@ -101,7 +99,7 @@ dev_dependencies:
isar_generator:
git:
url: https://github.com/immich-app/isar
ref: v3
ref: 'bb1dca40fe87a001122e5d43bc6254718cb49f3a'
path: packages/isar_generator/
integration_test:
sdk: flutter

View file

@ -19,7 +19,7 @@
"@oazapfts/runtime": "^1.0.2"
},
"devDependencies": {
"@types/node": "^22.18.1",
"@types/node": "^22.18.8",
"typescript": "^5.3.3"
},
"repository": {

340
pnpm-lock.yaml generated
View file

@ -63,11 +63,11 @@ importers:
specifier: ^4.13.1
version: 4.13.4
'@types/node':
specifier: ^22.18.1
version: 22.18.5
specifier: ^22.18.8
version: 22.18.8
'@vitest/coverage-v8':
specifier: ^3.0.0
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
byte-size:
specifier: ^9.0.0
version: 9.0.1
@ -109,16 +109,16 @@ importers:
version: 8.45.0(eslint@9.36.0(jiti@2.5.1))(typescript@5.9.2)
vite:
specifier: ^7.0.0
version: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
version: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite-tsconfig-paths:
specifier: ^5.0.0
version: 5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
version: 5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
vitest:
specifier: ^3.0.0
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vitest-fetch-mock:
specifier: ^0.4.0
version: 0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
version: 0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
yaml:
specifier: ^2.3.1
version: 2.8.1
@ -211,8 +211,8 @@ importers:
specifier: ^3.4.2
version: 3.7.1
'@types/node':
specifier: ^22.18.1
version: 22.18.5
specifier: ^22.18.8
version: 22.18.8
'@types/oidc-provider':
specifier: ^9.0.0
version: 9.5.0
@ -284,7 +284,7 @@ importers:
version: 5.2.1(encoding@0.1.13)
vitest:
specifier: ^3.0.0
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
open-api/typescript-sdk:
dependencies:
@ -293,8 +293,8 @@ importers:
version: 1.0.4
devDependencies:
'@types/node':
specifier: ^22.18.1
version: 22.18.5
specifier: ^22.18.8
version: 22.18.8
typescript:
specifier: ^5.3.3
version: 5.9.2
@ -450,7 +450,7 @@ importers:
version: 2.0.2
nest-commander:
specifier: ^3.16.0
version: 3.19.1(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@types/inquirer@8.2.11)(@types/node@22.18.5)(typescript@5.9.2)
version: 3.19.1(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@types/inquirer@8.2.11)(@types/node@22.18.8)(typescript@5.9.2)
nestjs-cls:
specifier: ^5.0.0
version: 5.4.3(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)
@ -462,7 +462,7 @@ importers:
version: 7.0.1(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)
nodemailer:
specifier: ^7.0.0
version: 7.0.6
version: 7.0.7
openid-client:
specifier: ^6.3.3
version: 6.8.0
@ -532,7 +532,7 @@ importers:
version: 9.36.0
'@nestjs/cli':
specifier: ^11.0.2
version: 11.0.10(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@22.18.5)
version: 11.0.10(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@22.18.8)
'@nestjs/schematics':
specifier: ^11.0.0
version: 11.0.7(chokidar@4.0.3)(typescript@5.9.2)
@ -582,8 +582,8 @@ importers:
specifier: ^2.0.0
version: 2.0.0
'@types/node':
specifier: ^22.18.1
version: 22.18.5
specifier: ^22.18.8
version: 22.18.8
'@types/nodemailer':
specifier: ^7.0.0
version: 7.0.1
@ -613,7 +613,7 @@ importers:
version: 13.15.3
'@vitest/coverage-v8':
specifier: ^3.0.0
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
eslint:
specifier: ^9.14.0
version: 9.36.0(jiti@2.5.1)
@ -667,10 +667,10 @@ importers:
version: 1.5.7(@swc/core@1.13.5(@swc/helpers@0.5.17))(rollup@4.50.1)
vite-tsconfig-paths:
specifier: ^5.0.0
version: 5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
version: 5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
vitest:
specifier: ^3.0.0
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
web:
dependencies:
@ -4519,8 +4519,8 @@ packages:
'@types/node@20.19.2':
resolution: {integrity: sha512-9pLGGwdzOUBDYi0GNjM97FIA+f92fqSke6joWeBjWXllfNxZBs7qeMF7tvtOIsbY45xkWkxrdwUfUf3MnQa9gA==}
'@types/node@22.18.5':
resolution: {integrity: sha512-g9BpPfJvxYBXUWI9bV37j6d6LTMNQ88hPwdWWUeYZnMhlo66FIg9gCc1/DZb15QylJSKwOZjwrckvOTWpOiChg==}
'@types/node@22.18.8':
resolution: {integrity: sha512-pAZSHMiagDR7cARo/cch1f3rXy0AEXwsVsVH09FcyeJVAzCnGgmYis7P3JidtTUjyadhTeSo8TgRPswstghDaw==}
'@types/node@24.5.1':
resolution: {integrity: sha512-/SQdmUP2xa+1rdx7VwB9yPq8PaKej8TD5cQ+XfKDPWWC+VDJU4rvVVagXqKUzhKjtFoNA8rXDJAkCxQPAe00+Q==}
@ -8398,8 +8398,8 @@ packages:
node-releases@2.0.19:
resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
nodemailer@7.0.6:
resolution: {integrity: sha512-F44uVzgwo49xboqbFgBGkRaiMgtoBrBEWCVincJPK9+S9Adkzt/wXCLKbf7dxucmxfTI5gHGB+bEmdyzN6QKjw==}
nodemailer@7.0.7:
resolution: {integrity: sha512-jGOaRznodf62TVzdyhKt/f1Q/c3kYynk8629sgJHpRzGZj01ezbgMMWJSAjHADcwTKxco3B68/R+KHJY2T5BaA==}
engines: {node: '>=6.0.0'}
nopt@1.0.10:
@ -11423,11 +11423,11 @@ snapshots:
optionalDependencies:
chokidar: 4.0.3
'@angular-devkit/schematics-cli@19.2.15(@types/node@22.18.5)(chokidar@4.0.3)':
'@angular-devkit/schematics-cli@19.2.15(@types/node@22.18.8)(chokidar@4.0.3)':
dependencies:
'@angular-devkit/core': 19.2.15(chokidar@4.0.3)
'@angular-devkit/schematics': 19.2.15(chokidar@4.0.3)
'@inquirer/prompts': 7.3.2(@types/node@22.18.5)
'@inquirer/prompts': 7.3.2(@types/node@22.18.8)
ansi-colors: 4.1.3
symbol-observable: 4.0.0
yargs-parser: 21.1.1
@ -14019,27 +14019,27 @@ snapshots:
transitivePeerDependencies:
- '@internationalized/date'
'@inquirer/checkbox@4.2.1(@types/node@22.18.5)':
'@inquirer/checkbox@4.2.1(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/figures': 1.0.13
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
ansi-escapes: 4.3.2
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/confirm@5.1.15(@types/node@22.18.5)':
'@inquirer/confirm@5.1.15(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/core@10.1.15(@types/node@22.18.5)':
'@inquirer/core@10.1.15(@types/node@22.18.8)':
dependencies:
'@inquirer/figures': 1.0.13
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
ansi-escapes: 4.3.2
cli-width: 4.1.0
mute-stream: 2.0.0
@ -14047,115 +14047,115 @@ snapshots:
wrap-ansi: 6.2.0
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/editor@4.2.17(@types/node@22.18.5)':
'@inquirer/editor@4.2.17(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/external-editor': 1.0.2(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/external-editor': 1.0.2(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/expand@4.0.17(@types/node@22.18.5)':
'@inquirer/expand@4.0.17(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/external-editor@1.0.2(@types/node@22.18.5)':
'@inquirer/external-editor@1.0.2(@types/node@22.18.8)':
dependencies:
chardet: 2.1.0
iconv-lite: 0.7.0
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/figures@1.0.13': {}
'@inquirer/input@4.2.1(@types/node@22.18.5)':
'@inquirer/input@4.2.1(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/number@3.0.17(@types/node@22.18.5)':
'@inquirer/number@3.0.17(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/password@4.0.17(@types/node@22.18.5)':
'@inquirer/password@4.0.17(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
ansi-escapes: 4.3.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/prompts@7.3.2(@types/node@22.18.5)':
'@inquirer/prompts@7.3.2(@types/node@22.18.8)':
dependencies:
'@inquirer/checkbox': 4.2.1(@types/node@22.18.5)
'@inquirer/confirm': 5.1.15(@types/node@22.18.5)
'@inquirer/editor': 4.2.17(@types/node@22.18.5)
'@inquirer/expand': 4.0.17(@types/node@22.18.5)
'@inquirer/input': 4.2.1(@types/node@22.18.5)
'@inquirer/number': 3.0.17(@types/node@22.18.5)
'@inquirer/password': 4.0.17(@types/node@22.18.5)
'@inquirer/rawlist': 4.1.5(@types/node@22.18.5)
'@inquirer/search': 3.1.0(@types/node@22.18.5)
'@inquirer/select': 4.3.1(@types/node@22.18.5)
'@inquirer/checkbox': 4.2.1(@types/node@22.18.8)
'@inquirer/confirm': 5.1.15(@types/node@22.18.8)
'@inquirer/editor': 4.2.17(@types/node@22.18.8)
'@inquirer/expand': 4.0.17(@types/node@22.18.8)
'@inquirer/input': 4.2.1(@types/node@22.18.8)
'@inquirer/number': 3.0.17(@types/node@22.18.8)
'@inquirer/password': 4.0.17(@types/node@22.18.8)
'@inquirer/rawlist': 4.1.5(@types/node@22.18.8)
'@inquirer/search': 3.1.0(@types/node@22.18.8)
'@inquirer/select': 4.3.1(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/prompts@7.8.0(@types/node@22.18.5)':
'@inquirer/prompts@7.8.0(@types/node@22.18.8)':
dependencies:
'@inquirer/checkbox': 4.2.1(@types/node@22.18.5)
'@inquirer/confirm': 5.1.15(@types/node@22.18.5)
'@inquirer/editor': 4.2.17(@types/node@22.18.5)
'@inquirer/expand': 4.0.17(@types/node@22.18.5)
'@inquirer/input': 4.2.1(@types/node@22.18.5)
'@inquirer/number': 3.0.17(@types/node@22.18.5)
'@inquirer/password': 4.0.17(@types/node@22.18.5)
'@inquirer/rawlist': 4.1.5(@types/node@22.18.5)
'@inquirer/search': 3.1.0(@types/node@22.18.5)
'@inquirer/select': 4.3.1(@types/node@22.18.5)
'@inquirer/checkbox': 4.2.1(@types/node@22.18.8)
'@inquirer/confirm': 5.1.15(@types/node@22.18.8)
'@inquirer/editor': 4.2.17(@types/node@22.18.8)
'@inquirer/expand': 4.0.17(@types/node@22.18.8)
'@inquirer/input': 4.2.1(@types/node@22.18.8)
'@inquirer/number': 3.0.17(@types/node@22.18.8)
'@inquirer/password': 4.0.17(@types/node@22.18.8)
'@inquirer/rawlist': 4.1.5(@types/node@22.18.8)
'@inquirer/search': 3.1.0(@types/node@22.18.8)
'@inquirer/select': 4.3.1(@types/node@22.18.8)
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/rawlist@4.1.5(@types/node@22.18.5)':
'@inquirer/rawlist@4.1.5(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/search@3.1.0(@types/node@22.18.5)':
'@inquirer/search@3.1.0(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/figures': 1.0.13
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/select@4.3.1(@types/node@22.18.5)':
'@inquirer/select@4.3.1(@types/node@22.18.8)':
dependencies:
'@inquirer/core': 10.1.15(@types/node@22.18.5)
'@inquirer/core': 10.1.15(@types/node@22.18.8)
'@inquirer/figures': 1.0.13
'@inquirer/type': 3.0.8(@types/node@22.18.5)
'@inquirer/type': 3.0.8(@types/node@22.18.8)
ansi-escapes: 4.3.2
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@inquirer/type@3.0.8(@types/node@22.18.5)':
'@inquirer/type@3.0.8(@types/node@22.18.8)':
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@internationalized/date@3.8.2':
dependencies:
@ -14193,7 +14193,7 @@ snapshots:
'@jest/schemas': 29.6.3
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/yargs': 17.0.33
chalk: 4.1.2
@ -14425,12 +14425,12 @@ snapshots:
bullmq: 5.58.5
tslib: 2.8.1
'@nestjs/cli@11.0.10(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@22.18.5)':
'@nestjs/cli@11.0.10(@swc/core@1.13.5(@swc/helpers@0.5.17))(@types/node@22.18.8)':
dependencies:
'@angular-devkit/core': 19.2.15(chokidar@4.0.3)
'@angular-devkit/schematics': 19.2.15(chokidar@4.0.3)
'@angular-devkit/schematics-cli': 19.2.15(@types/node@22.18.5)(chokidar@4.0.3)
'@inquirer/prompts': 7.8.0(@types/node@22.18.5)
'@angular-devkit/schematics-cli': 19.2.15(@types/node@22.18.8)(chokidar@4.0.3)
'@inquirer/prompts': 7.8.0(@types/node@22.18.8)
'@nestjs/schematics': 11.0.7(chokidar@4.0.3)(typescript@5.8.3)
ansis: 4.1.0
chokidar: 4.0.3
@ -15829,7 +15829,7 @@ snapshots:
'@types/accepts@1.3.7':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/archiver@6.0.3':
dependencies:
@ -15841,16 +15841,16 @@ snapshots:
'@types/bcrypt@6.0.0':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/body-parser@1.19.6':
dependencies:
'@types/connect': 3.4.38
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/bonjour@3.5.13':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/braces@3.0.5': {}
@ -15871,21 +15871,21 @@ snapshots:
'@types/cli-progress@3.11.6':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/compression@1.8.1':
dependencies:
'@types/express': 5.0.3
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/connect-history-api-fallback@1.5.4':
dependencies:
'@types/express-serve-static-core': 5.0.6
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/connect@3.4.38':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/content-disposition@0.5.9': {}
@ -15902,11 +15902,11 @@ snapshots:
'@types/connect': 3.4.38
'@types/express': 5.0.3
'@types/keygrip': 1.0.6
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/cors@2.8.19':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/debug@4.1.12':
dependencies:
@ -15916,13 +15916,13 @@ snapshots:
'@types/docker-modem@3.0.6':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ssh2': 1.15.5
'@types/dockerode@3.3.42':
dependencies:
'@types/docker-modem': 3.0.6
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ssh2': 1.15.5
'@types/dom-to-image@2.6.7': {}
@ -15945,14 +15945,14 @@ snapshots:
'@types/express-serve-static-core@4.19.6':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/qs': 6.14.0
'@types/range-parser': 1.2.7
'@types/send': 0.17.5
'@types/express-serve-static-core@5.0.6':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/qs': 6.14.0
'@types/range-parser': 1.2.7
'@types/send': 0.17.5
@ -15978,7 +15978,7 @@ snapshots:
'@types/fluent-ffmpeg@2.1.27':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/geojson-vt@3.2.5':
dependencies:
@ -16010,7 +16010,7 @@ snapshots:
'@types/http-proxy@1.17.16':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/inquirer@8.2.11':
dependencies:
@ -16048,7 +16048,7 @@ snapshots:
'@types/http-errors': 2.0.5
'@types/keygrip': 1.0.6
'@types/koa-compose': 3.2.8
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/leaflet@1.9.20':
dependencies:
@ -16080,7 +16080,7 @@ snapshots:
'@types/mock-fs@4.13.4':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ms@2.1.0': {}
@ -16090,7 +16090,7 @@ snapshots:
'@types/node-forge@1.3.11':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/node@17.0.45': {}
@ -16102,7 +16102,7 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@22.18.5':
'@types/node@22.18.8':
dependencies:
undici-types: 6.21.0
@ -16114,7 +16114,7 @@ snapshots:
'@types/nodemailer@7.0.1':
dependencies:
'@aws-sdk/client-sesv2': 3.890.0
'@types/node': 22.18.5
'@types/node': 22.18.8
transitivePeerDependencies:
- aws-crt
@ -16122,7 +16122,7 @@ snapshots:
dependencies:
'@types/keygrip': 1.0.6
'@types/koa': 3.0.0
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/parse5@5.0.3': {}
@ -16132,7 +16132,7 @@ snapshots:
'@types/pg@8.15.5':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
pg-protocol: 1.10.3
pg-types: 2.2.0
@ -16140,13 +16140,13 @@ snapshots:
'@types/pngjs@6.0.5':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/prismjs@1.26.5': {}
'@types/qrcode@1.5.5':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/qs@6.14.0': {}
@ -16175,7 +16175,7 @@ snapshots:
'@types/readdir-glob@1.1.5':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/retry@0.12.0': {}
@ -16185,14 +16185,14 @@ snapshots:
'@types/sax@1.2.7':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/semver@7.7.1': {}
'@types/send@0.17.5':
dependencies:
'@types/mime': 1.3.5
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/serve-index@1.9.4':
dependencies:
@ -16201,20 +16201,20 @@ snapshots:
'@types/serve-static@1.15.8':
dependencies:
'@types/http-errors': 2.0.5
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/send': 0.17.5
'@types/sockjs@0.3.36':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ssh2-streams@0.1.12':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ssh2@0.5.52':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ssh2-streams': 0.1.12
'@types/ssh2@1.15.5':
@ -16225,7 +16225,7 @@ snapshots:
dependencies:
'@types/cookiejar': 2.1.5
'@types/methods': 1.1.4
'@types/node': 22.18.5
'@types/node': 22.18.8
form-data: 4.0.4
'@types/supercluster@7.1.3':
@ -16239,7 +16239,7 @@ snapshots:
'@types/through@0.0.33':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/ua-parser-js@0.7.39': {}
@ -16255,7 +16255,7 @@ snapshots:
'@types/ws@8.18.1':
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
'@types/yargs-parser@21.0.3': {}
@ -16358,7 +16358,7 @@ snapshots:
'@ungap/structured-clone@1.3.0': {}
'@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))':
'@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))':
dependencies:
'@ampproject/remapping': 2.3.0
'@bcoe/v8-coverage': 1.0.2
@ -16373,7 +16373,7 @@ snapshots:
std-env: 3.9.0
test-exclude: 7.0.1
tinyrainbow: 2.0.0
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
@ -16404,13 +16404,13 @@ snapshots:
chai: 5.2.0
tinyrainbow: 2.0.0
'@vitest/mocker@3.2.4(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))':
'@vitest/mocker@3.2.4(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))':
dependencies:
'@vitest/spy': 3.2.4
estree-walker: 3.0.3
magic-string: 0.30.19
optionalDependencies:
vite: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
'@vitest/mocker@3.2.4(vite@7.1.5(@types/node@24.5.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))':
dependencies:
@ -17974,7 +17974,7 @@ snapshots:
engine.io@6.6.4:
dependencies:
'@types/cors': 2.8.19
'@types/node': 22.18.5
'@types/node': 22.18.8
accepts: 1.3.8
base64id: 2.0.0
cookie: 0.7.2
@ -18364,7 +18364,7 @@ snapshots:
eval@0.1.8:
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
require-like: 0.1.2
event-emitter@0.3.5:
@ -19343,9 +19343,9 @@ snapshots:
inline-style-parser@0.2.4: {}
inquirer@8.2.7(@types/node@22.18.5):
inquirer@8.2.7(@types/node@22.18.8):
dependencies:
'@inquirer/external-editor': 1.0.2(@types/node@22.18.5)
'@inquirer/external-editor': 1.0.2(@types/node@22.18.8)
ansi-escapes: 4.3.2
chalk: 4.1.2
cli-cursor: 3.1.0
@ -19549,7 +19549,7 @@ snapshots:
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
'@types/node': 22.18.5
'@types/node': 22.18.8
chalk: 4.1.2
ci-info: 3.9.0
graceful-fs: 4.2.11
@ -19557,13 +19557,13 @@ snapshots:
jest-worker@27.5.1:
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
merge-stream: 2.0.0
supports-color: 8.1.1
jest-worker@29.7.0:
dependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
jest-util: 29.7.0
merge-stream: 2.0.0
supports-color: 8.1.1
@ -20774,7 +20774,7 @@ snapshots:
neo-async@2.6.2: {}
nest-commander@3.19.1(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@types/inquirer@8.2.11)(@types/node@22.18.5)(typescript@5.9.2):
nest-commander@3.19.1(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@types/inquirer@8.2.11)(@types/node@22.18.8)(typescript@5.9.2):
dependencies:
'@fig/complete-commander': 3.2.0(commander@11.1.0)
'@golevelup/nestjs-discovery': 4.0.3(@nestjs/common@11.1.6(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)
@ -20783,7 +20783,7 @@ snapshots:
'@types/inquirer': 8.2.11
commander: 11.1.0
cosmiconfig: 8.3.6(typescript@5.9.2)
inquirer: 8.2.7(@types/node@22.18.5)
inquirer: 8.2.7(@types/node@22.18.8)
transitivePeerDependencies:
- '@types/node'
- typescript
@ -20873,7 +20873,7 @@ snapshots:
node-releases@2.0.19: {}
nodemailer@7.0.6: {}
nodemailer@7.0.7: {}
nopt@1.0.10:
dependencies:
@ -21871,7 +21871,7 @@ snapshots:
'@protobufjs/path': 1.1.2
'@protobufjs/pool': 1.1.0
'@protobufjs/utf8': 1.1.0
'@types/node': 22.18.5
'@types/node': 22.18.8
long: 5.3.2
protocol-buffers-schema@3.6.0: {}
@ -23737,13 +23737,13 @@ snapshots:
- rollup
- supports-color
vite-node@3.2.4(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
vite-node@3.2.4(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 2.0.3
vite: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
transitivePeerDependencies:
- '@types/node'
- jiti
@ -23779,18 +23779,18 @@ snapshots:
- tsx
- yaml
vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)):
vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.2)
optionalDependencies:
vite: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
- typescript
vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
dependencies:
esbuild: 0.25.9
fdir: 6.5.0(picomatch@4.0.3)
@ -23799,7 +23799,7 @@ snapshots:
rollup: 4.50.1
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.18.5
'@types/node': 22.18.8
fsevents: 2.3.3
jiti: 2.5.1
lightningcss: 1.30.1
@ -23826,15 +23826,15 @@ snapshots:
optionalDependencies:
vite: 7.1.5(@types/node@24.5.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vitest-fetch-mock@0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)):
vitest-fetch-mock@0.4.5(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)):
dependencies:
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
dependencies:
'@types/chai': 5.2.2
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
'@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@ -23852,12 +23852,12 @@ snapshots:
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 22.18.5
'@types/node': 22.18.8
happy-dom: 18.0.1
jsdom: 26.1.0(canvas@2.11.2(encoding@0.1.13))
transitivePeerDependencies:
@ -23874,11 +23874,11 @@ snapshots:
- tsx
- yaml
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.5)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.8)(happy-dom@18.0.1)(jiti@2.5.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1):
dependencies:
'@types/chai': 5.2.2
'@vitest/expect': 3.2.4
'@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
'@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1))
'@vitest/pretty-format': 3.2.4
'@vitest/runner': 3.2.4
'@vitest/snapshot': 3.2.4
@ -23896,12 +23896,12 @@ snapshots:
tinyglobby: 0.2.15
tinypool: 1.1.1
tinyrainbow: 2.0.0
vite: 7.1.5(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@22.18.5)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite: 7.1.5(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
vite-node: 3.2.4(@types/node@22.18.8)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.43.1)(yaml@2.8.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/debug': 4.1.12
'@types/node': 22.18.5
'@types/node': 22.18.8
happy-dom: 18.0.1
jsdom: 26.1.0(canvas@2.11.2)
transitivePeerDependencies:

View file

@ -1,35 +1,50 @@
FROM ghcr.io/immich-app/base-server-dev:202509210934@sha256:b5ce2d7eaf379d4cf15efd4bab180d8afc8a80d20b36c9800f4091aca6ae267e AS builder
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
CI=1 \
COREPACK_HOME=/tmp
COREPACK_HOME=/tmp \
PNPM_HOME=/buildcache/pnpm-store \
PATH="/buildcache/pnpm-store:$PATH"
RUN npm install --global corepack@latest && \
corepack enable pnpm
corepack enable pnpm && \
pnpm config set store-dir "$PNPM_HOME"
FROM builder AS server
WORKDIR /usr/src/app
COPY ./package* ./pnpm* .pnpmfile.cjs ./
COPY ./server ./server/
RUN SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter immich --frozen-lockfile build && \
RUN --mount=type=cache,id=pnpm-server,target=/buildcache/pnpm-store \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=.pnpmfile.cjs,target=.pnpmfile.cjs \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
--mount=type=bind,source=pnpm-workspace.yaml,target=pnpm-workspace.yaml \
SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter immich --frozen-lockfile build && \
SHARP_FORCE_GLOBAL_LIBVIPS=true pnpm --filter immich --frozen-lockfile --prod --no-optional deploy /output/server-pruned
FROM builder AS web
WORKDIR /usr/src/app
COPY ./package* ./pnpm* .pnpmfile.cjs ./
COPY ./web ./web/
COPY ./i18n ./i18n/
COPY ./open-api ./open-api/
RUN SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter @immich/sdk --filter immich-web --frozen-lockfile --force install && \
RUN --mount=type=cache,id=pnpm-web,target=/buildcache/pnpm-store \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=.pnpmfile.cjs,target=.pnpmfile.cjs \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
--mount=type=bind,source=pnpm-workspace.yaml,target=pnpm-workspace.yaml \
SHARP_IGNORE_GLOBAL_LIBVIPS=true pnpm --filter @immich/sdk --filter immich-web --frozen-lockfile --force install && \
pnpm --filter @immich/sdk --filter immich-web build
FROM builder AS cli
COPY ./package* ./pnpm* .pnpmfile.cjs ./
COPY ./cli ./cli/
COPY ./open-api ./open-api/
RUN pnpm --filter @immich/sdk --filter @immich/cli --frozen-lockfile install && \
RUN --mount=type=cache,id=pnpm-cli,target=/buildcache/pnpm-store \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=.pnpmfile.cjs,target=.pnpmfile.cjs \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
--mount=type=bind,source=pnpm-workspace.yaml,target=pnpm-workspace.yaml \
pnpm --filter @immich/sdk --filter @immich/cli --frozen-lockfile install && \
pnpm --filter @immich/sdk --filter @immich/cli build && \
pnpm --filter @immich/cli --prod --no-optional deploy /output/cli-pruned

View file

@ -129,7 +129,7 @@
"@types/luxon": "^3.6.2",
"@types/mock-fs": "^4.13.1",
"@types/multer": "^2.0.0",
"@types/node": "^22.18.1",
"@types/node": "^22.18.8",
"@types/nodemailer": "^7.0.0",
"@types/picomatch": "^4.0.0",
"@types/pngjs": "^6.0.5",

View file

@ -82,11 +82,6 @@ export class DayGroup {
return this.viewerAssets[0]?.asset;
}
getRandomAsset() {
const random = Math.floor(Math.random() * this.viewerAssets.length);
return this.viewerAssets[random];
}
*assetsIterator(options: { startAsset?: TimelineAsset; direction?: Direction } = {}) {
const isEarlier = (options?.direction ?? 'earlier') === 'earlier';
let assetIndex = options?.startAsset

View file

@ -233,15 +233,6 @@ export class MonthGroup {
addContext.changedDayGroups.add(dayGroup);
}
getRandomDayGroup() {
const random = Math.floor(Math.random() * this.dayGroups.length);
return this.dayGroups[random];
}
getRandomAsset() {
return this.getRandomDayGroup()?.getRandomAsset()?.asset;
}
get viewId() {
const { year, month } = this.yearMonth;
return year + '-' + month;

View file

@ -580,4 +580,60 @@ describe('TimelineManager', () => {
expect(timelineManager.getMonthGroupByAssetId(assetOne.id)?.yearMonth.month).toEqual(1);
});
});
describe('getRandomAsset', () => {
let timelineManager: TimelineManager;
const bucketAssets: Record<string, TimelineAsset[]> = {
'2024-03-01T00:00:00.000Z': timelineAssetFactory.buildList(1).map((asset) =>
deriveLocalDateTimeFromFileCreatedAt({
...asset,
fileCreatedAt: fromISODateTimeUTCToObject('2024-03-01T00:00:00.000Z'),
}),
),
'2024-02-01T00:00:00.000Z': timelineAssetFactory.buildList(10).map((asset, idx) =>
deriveLocalDateTimeFromFileCreatedAt({
...asset,
// here we make sure that not all assets are on the first day of the month
fileCreatedAt: fromISODateTimeUTCToObject(`2024-02-0${idx < 7 ? 1 : 2}T00:00:00.000Z`),
}),
),
'2024-01-01T00:00:00.000Z': timelineAssetFactory.buildList(3).map((asset) =>
deriveLocalDateTimeFromFileCreatedAt({
...asset,
fileCreatedAt: fromISODateTimeUTCToObject('2024-01-01T00:00:00.000Z'),
}),
),
};
const bucketAssetsResponse: Record<string, TimeBucketAssetResponseDto> = Object.fromEntries(
Object.entries(bucketAssets).map(([key, assets]) => [key, toResponseDto(...assets)]),
);
beforeEach(async () => {
timelineManager = new TimelineManager();
sdkMock.getTimeBuckets.mockResolvedValue([
{ count: 1, timeBucket: '2024-03-01' },
{ count: 10, timeBucket: '2024-02-01' },
{ count: 3, timeBucket: '2024-01-01' },
]);
sdkMock.getTimeBucket.mockImplementation(({ timeBucket }) => Promise.resolve(bucketAssetsResponse[timeBucket]));
await timelineManager.updateViewport({ width: 1588, height: 0 });
});
it('gets all assets once', async () => {
const assetCount = timelineManager.assetCount;
expect(assetCount).toBe(14);
const discoveredAssets: Set<string> = new Set();
for (let idx = 0; idx < assetCount; idx++) {
const asset = await timelineManager.getRandomAsset(idx);
expect(asset).toBeDefined();
const id = asset!.id;
expect(discoveredAssets.has(id)).toBeFalsy();
discoveredAssets.add(id);
}
expect(discoveredAssets.size).toBe(assetCount);
});
});
});

View file

@ -451,16 +451,42 @@ export class TimelineManager {
return monthGroupInfo?.monthGroup;
}
async getRandomMonthGroup() {
const random = Math.floor(Math.random() * this.months.length);
const month = this.months[random];
await this.loadMonthGroup(month.yearMonth, { cancelable: false });
return month;
// note: the `index` input is expected to be in the range [0, assetCount). This
// value can be passed to make the method deterministic, which is mainly useful
// for testing.
async getRandomAsset(index?: number): Promise<TimelineAsset | undefined> {
const randomAssetIndex = index ?? Math.floor(Math.random() * this.assetCount);
let accumulatedCount = 0;
let randomMonth: MonthGroup | undefined = undefined;
for (const month of this.months) {
if (randomAssetIndex < accumulatedCount + month.assetsCount) {
randomMonth = month;
break;
}
async getRandomAsset() {
const month = await this.getRandomMonthGroup();
return month?.getRandomAsset();
accumulatedCount += month.assetsCount;
}
if (!randomMonth) {
return;
}
await this.loadMonthGroup(randomMonth.yearMonth, { cancelable: false });
let randomDay: DayGroup | undefined = undefined;
for (const day of randomMonth.dayGroups) {
if (randomAssetIndex < accumulatedCount + day.viewerAssets.length) {
randomDay = day;
break;
}
accumulatedCount += day.viewerAssets.length;
}
if (!randomDay) {
return;
}
return randomDay.viewerAssets[randomAssetIndex - accumulatedCount].asset;
}
updateAssetOperation(ids: string[], operation: AssetOperation) {