Compare commits

..

1 Commits

Author SHA1 Message Date
renovate[bot] 268de31729 fix(deps): update typescript-projects 2026-07-06 21:09:07 +00:00
24 changed files with 46 additions and 14461 deletions
+1 -1
View File
@@ -28,4 +28,4 @@ run = "prettier --write ."
run = "wrangler pages deploy build --project-name=${PROJECT_NAME} --branch=${BRANCH_NAME}"
[tools]
wrangler = "4.100.0"
wrangler = "4.106.0"
+19 -19
View File
@@ -287,43 +287,43 @@ url = "https://github.com/opentofu/opentofu/releases/download/v1.11.6/tofu_1.11.
url_api = "https://api.github.com/repos/opentofu/opentofu/releases/assets/391536406"
[[tools.pnpm]]
version = "11.6.0"
version = "11.9.0"
backend = "aqua:pnpm/pnpm"
[tools.pnpm."platforms.linux-arm64"]
checksum = "sha256:2fec653ff6dadab340d1c3d2214688a7451cc471f39710839440b293ca7c53b0"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-arm64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120174"
checksum = "sha256:7981d0109fffdf8f15b838243240c8c9f9114dd4b7111d4227c1453522d75b61"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-linux-arm64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748044"
provenance = "github-attestations"
[tools.pnpm."platforms.linux-arm64-musl"]
checksum = "sha256:56a78c08cf22adf29e7dacb6f7f100139731693863d20fb94a7883463a62169e"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-arm64-musl.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120177"
checksum = "sha256:3622d3010d6af601190e7b63994fb0fe297e805699145aec949f4879f2672fb5"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-linux-arm64-musl.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748040"
provenance = "github-attestations"
[tools.pnpm."platforms.linux-x64"]
checksum = "sha256:74d64c1646385fb21691f32f0ab6aca1a9f5c829ba54d3cda3a24838a228e68c"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-x64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120176"
checksum = "sha256:8d987d82585453bcf260ea5d0bae346d298f1a5e71bcde8d99976521408ad895"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-linux-x64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748039"
provenance = "github-attestations"
[tools.pnpm."platforms.linux-x64-musl"]
checksum = "sha256:7a0c463a09d912fba6b7d9eca0a946bc228ea50f3015a05c09a29e7e85a932d7"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-linux-x64-musl.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120175"
checksum = "sha256:655fcf2609e3145cfd7c2f05113429523706d0a618f2957eaa6c3562f6a5998b"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-linux-x64-musl.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748037"
provenance = "github-attestations"
[tools.pnpm."platforms.macos-arm64"]
checksum = "sha256:87c901635a14481fb30566a3749041134ffd4317bc6fe866c345b69fdf9b6b85"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-darwin-arm64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120180"
checksum = "sha256:ca6f98a8911ec975509464026205e2b54aed74cecd36c5ae9932e5997bd7de2a"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-darwin-arm64.tar.gz"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748038"
provenance = "github-attestations"
[tools.pnpm."platforms.windows-x64"]
checksum = "sha256:91c753435542b04859c689304fae0dd64eba6b40937cfa426a48485b712e4e9c"
url = "https://github.com/pnpm/pnpm/releases/download/v11.6.0/pnpm-win32-x64.zip"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/445120173"
checksum = "sha256:82c130717a59f237c49e8eaa8a7ed75c1d8d351a5b6dedeee3196b8e1b597c6e"
url = "https://github.com/pnpm/pnpm/releases/download/v11.9.0/pnpm-win32-x64.zip"
url_api = "https://api.github.com/repos/pnpm/pnpm/releases/assets/455748043"
provenance = "github-attestations"
[[tools.terragrunt]]
+1 -1
View File
@@ -16,7 +16,7 @@ config_roots = [
[tools]
node = "24.15.0"
pnpm = "11.6.0"
pnpm = "11.9.0"
terragrunt = "1.0.3"
opentofu = "1.11.6"
"npm:oazapfts" = "7.5.0"
@@ -107,67 +107,3 @@ Java_app_alextran_immich_NativeImage_rotate(
}
return (jlong) dst;
}
// Convert an RGBA_1010102 buffer to densely-packed RGBA_8888, matching Skia's
// Bitmap.copy(ARGB_8888) byte-for-byte so it's a drop-in for the intermediate 8888 bitmap.
// Each source pixel is a native (little-endian on every Android ABI) u32 with R in bits 0-9,
// G in 10-19, B in 20-29, A in 30-31 (standard RGB10_A2). Each 10-bit channel maps to 8-bit via
// round(v*255/1023). The 2-bit alpha maps to a*85. Both are kept as plain arithmetic as the whole
// loop auto-vectorizes to NEON and measures faster than a LUT on-device. Output is R,G,B,A bytes
// per pixel, i.e. Android ARGB_8888 memory == Dart PixelFormat.rgba8888.
static void convert_1010102(const uint8_t *src, int srcStride, uint32_t *dst, int w, int h) {
for (int y = 0; y < h; y++) {
const uint32_t *srcRow = (const uint32_t *) (src + (size_t) y * srcStride);
uint32_t *dstRow = dst + (size_t) y * w;
for (int x = 0; x < w; x++) {
uint32_t px = srcRow[x];
uint32_t r = ((px & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t g = (((px >> 10) & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t b = (((px >> 20) & 0x3FF) * 16336u + 32768u) >> 16;
uint32_t a = ((px >> 30) & 0x3) * 85u;
dstRow[x] = r | (g << 8) | (b << 16) | (a << 24);
}
}
}
// Converts an RGBA_1010102 bitmap (what a 10-bit HEIC/AVIF decodes to on API 33+) into a freshly
// malloc'd RGBA_8888 buffer. Fills outInfo with {width, height, rowBytes} and returns the buffer
// address, or 0 (so the caller falls back to a Skia copy) if the bitmap isn't 1010102 or can't be
// locked. Same ownership contract as rotate: free the returned buffer via NativeBuffer.free.
JNIEXPORT jlong JNICALL
Java_app_alextran_immich_NativeImage_convert1010102(
JNIEnv *env, jclass clazz, jobject bitmap, jintArray outInfo) {
AndroidBitmapInfo info;
if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS) {
return 0;
}
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_1010102) {
return 0;
}
int w = (int) info.width;
int h = (int) info.height;
uint32_t *dst = (uint32_t *) malloc((size_t) w * h * 4);
if (dst == NULL) {
return 0;
}
void *srcPixels = NULL;
if (AndroidBitmap_lockPixels(env, bitmap, &srcPixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
free(dst);
return 0;
}
convert_1010102((const uint8_t *) srcPixels, (int) info.stride, dst, w, h);
AndroidBitmap_unlockPixels(env, bitmap);
jint dims[3] = {w, h, w * 4};
(*env)->SetIntArrayRegion(env, outInfo, 0, 3, dims);
if ((*env)->ExceptionCheck(env)) {
free(dst);
return 0;
}
return (jlong) dst;
}
@@ -16,14 +16,4 @@ object NativeImage {
*/
@JvmStatic
external fun rotate(bitmap: Bitmap, orientation: Int, outInfo: IntArray): Long
/**
* Converts an RGBA_1010102 [bitmap] (what a 10-bit HEIC/AVIF decodes to on API 33+) to RGBA_8888,
* writing the result into a freshly malloc'd native buffer in one pass, with no intermediate
* ARGB_8888 bitmap. Returns the buffer address (free it with [NativeBuffer.free]) and fills
* [outInfo] with {width, height, rowBytes}. Returns 0 when the bitmap isn't RGBA_1010102 so the
* caller can fall back to a Skia copy.
*/
@JvmStatic
external fun convert1010102(bitmap: Bitmap, outInfo: IntArray): Long
}
@@ -46,47 +46,22 @@ inline fun ImageDecoder.Source.decodeBitmap(target: Size = Size(0, 0)): Bitmap {
}
fun Bitmap.toNativeBuffer(): Map<String, Long> {
// Dart reads the buffer as rgba8888, but 10-bit sources decode to RGBA_1010102, which garbles
// colors when copied verbatim. Convert those straight into the output buffer in native code -
// one pass, no intermediate ARGB_8888 bitmap.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && config == Bitmap.Config.RGBA_1010102) {
val info = IntArray(3)
val pointer = NativeImage.convert1010102(this, info)
if (pointer != 0L) {
recycle()
return mapOf(
"pointer" to pointer,
"width" to info[0].toLong(),
"height" to info[1].toLong(),
"rowBytes" to info[2].toLong()
)
}
// native convert declined (OOM/lock) -> fall through to the Skia copy path below.
}
// Other non-8888 configs (e.g. HDR F16) still need Skia's convert; 8-bit is copied as-is.
val bitmap = if (config != Bitmap.Config.ARGB_8888) {
val converted = copy(Bitmap.Config.ARGB_8888, false)
recycle()
converted ?: throw IOException("could not convert bitmap to ARGB_8888")
} else {
this
}
val size = bitmap.width * bitmap.height * 4
val size = width * height * 4
val pointer = NativeBuffer.allocate(size)
try {
val buffer = NativeBuffer.wrap(pointer, size)
bitmap.copyPixelsToBuffer(buffer)
copyPixelsToBuffer(buffer)
return mapOf(
"pointer" to pointer,
"width" to bitmap.width.toLong(),
"height" to bitmap.height.toLong(),
"rowBytes" to (bitmap.width * 4).toLong()
"width" to width.toLong(),
"height" to height.toLong(),
"rowBytes" to (width * 4).toLong()
)
} catch (e: Throwable) {
} catch (e: Exception) {
NativeBuffer.free(pointer)
throw e
} finally {
bitmap.recycle()
recycle()
}
}
@@ -1,8 +1,6 @@
package app.alextran.immich.images
import android.content.Context
import android.graphics.ImageDecoder
import android.os.Build
import android.os.CancellationSignal
import android.os.OperationCanceledException
import app.alextran.immich.INITIAL_BUFFER_SIZE
@@ -24,7 +22,6 @@ import java.io.File
import java.io.IOException
import java.nio.ByteBuffer
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executors
private const val MAX_PREALLOC_BYTES = 128 * 1024 * 1024
@@ -39,16 +36,12 @@ class RemoteImagesImpl(context: Context) : RemoteImageApi {
companion object {
val CANCELLED = Result.success<Map<String, Long>?>(null)
// Shared, process-lifetime pool: RemoteImagesImpl is re-created per FlutterEngine, so a
// per-instance pool would leak threads across engine restarts.
private val decodeExecutor = Executors.newFixedThreadPool(2)
}
override fun requestImage(
url: String,
requestId: Long,
preferEncoded: Boolean,
@Suppress("UNUSED_PARAMETER") preferEncoded: Boolean, // always returns encoded; setting has no effect on Android
callback: (Result<Map<String, Long>?>) -> Unit
) {
val signal = CancellationSignal()
@@ -58,51 +51,12 @@ class RemoteImagesImpl(context: Context) : RemoteImageApi {
url,
signal,
onSuccess = { buffer ->
requestMap.remove(requestId)
if (signal.isCanceled) {
requestMap.remove(requestId)
buffer.free()
NativeBuffer.free(buffer.pointer)
return@fetch callback(CANCELLED)
}
// Decode natively when the caller wants pixels: Flutter's fallback decoder copies
// 10-bit bitmaps (RGBA_1010102) as if they were rgba8888, garbling colors. Decode on a
// dedicated pool - the fetch callback threads are shared with video streaming. On any
// decode failure (including OOM on huge originals), hand Flutter the encoded bytes as
// before.
if (!preferEncoded && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
decodeExecutor.execute {
val res = if (signal.isCanceled) null else try {
val source = ImageDecoder.createSource(NativeBuffer.wrap(buffer.pointer, buffer.offset))
source.decodeBitmap().toNativeBuffer()
} catch (_: Throwable) {
null
}
requestMap.remove(requestId)
when {
// Deliver even if the request was cancelled meanwhile: re-checking here would orphan
// res's malloc, and Dart frees the buffer itself when it sees the cancel.
res != null -> {
buffer.free()
callback(Result.success(res))
}
signal.isCanceled -> {
buffer.free()
callback(CANCELLED)
}
else -> callback(
Result.success(
mapOf(
"pointer" to buffer.pointer,
"length" to buffer.offset.toLong()
)
)
)
}
}
return@fetch
}
requestMap.remove(requestId)
callback(
Result.success(
mapOf(
File diff suppressed because it is too large Load Diff
@@ -21,7 +21,6 @@ WHERE (library_id IS NOT NULL);
CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_visibility_deleted_created
ON remote_asset_entity (owner_id, visibility, deleted_at, created_at DESC)
''')
@TableIndex.sql('CREATE INDEX IF NOT EXISTS idx_remote_asset_uploaded ON remote_asset_entity (uploaded_at)')
class RemoteAssetEntity extends Table with DriftDefaultsMixin, AssetEntityMixin {
const RemoteAssetEntity();
@@ -1779,7 +1779,3 @@ i0.Index get idxRemoteAssetOwnerVisibilityDeletedCreated => i0.Index(
'idx_remote_asset_owner_visibility_deleted_created',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_visibility_deleted_created ON remote_asset_entity (owner_id, visibility, deleted_at, created_at DESC)',
);
i0.Index get idxRemoteAssetUploaded => i0.Index(
'idx_remote_asset_uploaded',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_uploaded ON remote_asset_entity (uploaded_at)',
);
@@ -12,7 +12,7 @@ class RemoteImageRequest extends ImageRequest {
}
final info = await remoteImageApi.requestImage(uri, requestId: requestId, preferEncoded: false);
// Android falls back to encoded data if native decoding fails, so check for both shapes of the response.
// Android always returns encoded data, so we need to check for both shapes of the response.
final frame = switch (info) {
{'pointer': int pointer, 'length': int length} => await _fromEncodedPlatformImage(pointer, length),
{'pointer': int pointer, 'width': int width, 'height': int height, 'rowBytes': int rowBytes} =>
@@ -120,7 +120,7 @@ class Drift extends $Drift {
}
@override
int get schemaVersion => 31;
int get schemaVersion => 30;
@override
MigrationStrategy get migration => MigrationStrategy(
@@ -311,9 +311,6 @@ class Drift extends $Drift {
from29To30: (m, v30) async {
await m.alterTable(TableMigration(v30.settings));
},
from30To31: (m, v31) async {
await m.createIndex(v31.idxRemoteAssetUploaded);
},
),
);
@@ -124,7 +124,6 @@ abstract class $Drift extends i0.GeneratedDatabase {
i2.idxRemoteAssetChecksum,
i2.idxRemoteAssetStackId,
i2.idxRemoteAssetOwnerVisibilityDeletedCreated,
i2.idxRemoteAssetUploaded,
authUserEntity,
userMetadataEntity,
partnerEntity,
@@ -15920,592 +15920,6 @@ i1.GeneratedColumn<String> _column_224(String aliasedName) =>
type: i1.DriftSqlType.string,
$customConstraints: 'NULL',
);
final class Schema31 extends i0.VersionedSchema {
Schema31({required super.database}) : super(version: 31);
@override
late final List<i1.DatabaseSchemaEntity> entities = [
userEntity,
remoteAssetEntity,
stackEntity,
localAssetEntity,
remoteAlbumEntity,
localAlbumEntity,
localAlbumAssetEntity,
idxLocalAlbumAssetAlbumAsset,
idxLocalAssetChecksum,
idxLocalAssetCloudId,
idxLocalAssetCreatedAt,
idxStackPrimaryAssetId,
uQRemoteAssetsOwnerChecksum,
uQRemoteAssetsOwnerLibraryChecksum,
idxRemoteAssetChecksum,
idxRemoteAssetStackId,
idxRemoteAssetOwnerVisibilityDeletedCreated,
idxRemoteAssetUploaded,
authUserEntity,
userMetadataEntity,
partnerEntity,
remoteExifEntity,
remoteAlbumAssetEntity,
remoteAlbumUserEntity,
remoteAssetCloudIdEntity,
memoryEntity,
memoryAssetEntity,
personEntity,
assetFaceEntity,
storeEntity,
trashedLocalAssetEntity,
assetEditEntity,
settings,
assetOcrEntity,
idxPartnerSharedWithId,
idxLatLng,
idxRemoteExifCity,
idxRemoteAlbumAssetAlbumAsset,
idxRemoteAssetCloudId,
idxPersonOwnerId,
idxAssetFacePersonId,
idxAssetFaceAssetId,
idxAssetFaceVisiblePerson,
idxTrashedLocalAssetChecksum,
idxTrashedLocalAssetAlbum,
idxAssetEditAssetId,
idxAssetOcrAssetId,
];
late final Shape33 userEntity = Shape33(
source: i0.VersionedTable(
entityName: 'user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_108,
_column_109,
_column_110,
_column_111,
_column_112,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape50 remoteAssetEntity = Shape50(
source: i0.VersionedTable(
entityName: 'remote_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_108,
_column_113,
_column_114,
_column_115,
_column_116,
_column_117,
_column_118,
_column_107,
_column_119,
_column_120,
_column_121,
_column_122,
_column_123,
_column_124,
_column_212,
_column_125,
_column_126,
_column_127,
_column_128,
_column_129,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape35 stackEntity = Shape35(
source: i0.VersionedTable(
entityName: 'stack_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_114,
_column_115,
_column_121,
_column_130,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape36 localAssetEntity = Shape36(
source: i0.VersionedTable(
entityName: 'local_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_108,
_column_113,
_column_114,
_column_115,
_column_116,
_column_117,
_column_118,
_column_107,
_column_131,
_column_120,
_column_132,
_column_133,
_column_134,
_column_135,
_column_136,
_column_137,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape48 remoteAlbumEntity = Shape48(
source: i0.VersionedTable(
entityName: 'remote_album_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_108,
_column_138,
_column_114,
_column_115,
_column_139,
_column_140,
_column_141,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape38 localAlbumEntity = Shape38(
source: i0.VersionedTable(
entityName: 'local_album_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_108,
_column_115,
_column_142,
_column_143,
_column_144,
_column_145,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape39 localAlbumAssetEntity = Shape39(
source: i0.VersionedTable(
entityName: 'local_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id, album_id)'],
columns: [_column_146, _column_147, _column_145],
attachedDatabase: database,
),
alias: null,
);
final i1.Index idxLocalAlbumAssetAlbumAsset = i1.Index(
'idx_local_album_asset_album_asset',
'CREATE INDEX IF NOT EXISTS idx_local_album_asset_album_asset ON local_album_asset_entity (album_id, asset_id)',
);
final i1.Index idxLocalAssetChecksum = i1.Index(
'idx_local_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_local_asset_checksum ON local_asset_entity (checksum)',
);
final i1.Index idxLocalAssetCloudId = i1.Index(
'idx_local_asset_cloud_id',
'CREATE INDEX IF NOT EXISTS idx_local_asset_cloud_id ON local_asset_entity (i_cloud_id)',
);
final i1.Index idxLocalAssetCreatedAt = i1.Index(
'idx_local_asset_created_at',
'CREATE INDEX IF NOT EXISTS idx_local_asset_created_at ON local_asset_entity (created_at)',
);
final i1.Index idxStackPrimaryAssetId = i1.Index(
'idx_stack_primary_asset_id',
'CREATE INDEX IF NOT EXISTS idx_stack_primary_asset_id ON stack_entity (primary_asset_id)',
);
final i1.Index uQRemoteAssetsOwnerChecksum = i1.Index(
'UQ_remote_assets_owner_checksum',
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_checksum ON remote_asset_entity (owner_id, checksum) WHERE(library_id IS NULL)',
);
final i1.Index uQRemoteAssetsOwnerLibraryChecksum = i1.Index(
'UQ_remote_assets_owner_library_checksum',
'CREATE UNIQUE INDEX IF NOT EXISTS UQ_remote_assets_owner_library_checksum ON remote_asset_entity (owner_id, library_id, checksum) WHERE(library_id IS NOT NULL)',
);
final i1.Index idxRemoteAssetChecksum = i1.Index(
'idx_remote_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_checksum ON remote_asset_entity (checksum)',
);
final i1.Index idxRemoteAssetStackId = i1.Index(
'idx_remote_asset_stack_id',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_stack_id ON remote_asset_entity (stack_id)',
);
final i1.Index idxRemoteAssetOwnerVisibilityDeletedCreated = i1.Index(
'idx_remote_asset_owner_visibility_deleted_created',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_owner_visibility_deleted_created ON remote_asset_entity (owner_id, visibility, deleted_at, created_at DESC)',
);
final i1.Index idxRemoteAssetUploaded = i1.Index(
'idx_remote_asset_uploaded',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_uploaded ON remote_asset_entity (uploaded_at)',
);
late final Shape40 authUserEntity = Shape40(
source: i0.VersionedTable(
entityName: 'auth_user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_108,
_column_109,
_column_148,
_column_110,
_column_111,
_column_149,
_column_150,
_column_151,
_column_152,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape4 userMetadataEntity = Shape4(
source: i0.VersionedTable(
entityName: 'user_metadata_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(user_id, "key")'],
columns: [_column_153, _column_154, _column_155],
attachedDatabase: database,
),
alias: null,
);
late final Shape41 partnerEntity = Shape41(
source: i0.VersionedTable(
entityName: 'partner_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(shared_by_id, shared_with_id)'],
columns: [_column_156, _column_157, _column_158],
attachedDatabase: database,
),
alias: null,
);
late final Shape42 remoteExifEntity = Shape42(
source: i0.VersionedTable(
entityName: 'remote_exif_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id)'],
columns: [
_column_159,
_column_160,
_column_161,
_column_162,
_column_163,
_column_164,
_column_117,
_column_116,
_column_165,
_column_166,
_column_167,
_column_168,
_column_135,
_column_136,
_column_169,
_column_170,
_column_171,
_column_172,
_column_173,
_column_174,
_column_175,
_column_176,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape7 remoteAlbumAssetEntity = Shape7(
source: i0.VersionedTable(
entityName: 'remote_album_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id, album_id)'],
columns: [_column_159, _column_177],
attachedDatabase: database,
),
alias: null,
);
late final Shape10 remoteAlbumUserEntity = Shape10(
source: i0.VersionedTable(
entityName: 'remote_album_user_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(album_id, user_id)'],
columns: [_column_177, _column_153, _column_178],
attachedDatabase: database,
),
alias: null,
);
late final Shape43 remoteAssetCloudIdEntity = Shape43(
source: i0.VersionedTable(
entityName: 'remote_asset_cloud_id_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id)'],
columns: [
_column_159,
_column_179,
_column_180,
_column_134,
_column_135,
_column_136,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape44 memoryEntity = Shape44(
source: i0.VersionedTable(
entityName: 'memory_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_114,
_column_115,
_column_124,
_column_121,
_column_113,
_column_181,
_column_182,
_column_183,
_column_184,
_column_185,
_column_186,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape12 memoryAssetEntity = Shape12(
source: i0.VersionedTable(
entityName: 'memory_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(asset_id, memory_id)'],
columns: [_column_159, _column_187],
attachedDatabase: database,
),
alias: null,
);
late final Shape45 personEntity = Shape45(
source: i0.VersionedTable(
entityName: 'person_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_114,
_column_115,
_column_121,
_column_108,
_column_188,
_column_189,
_column_190,
_column_191,
_column_192,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape46 assetFaceEntity = Shape46(
source: i0.VersionedTable(
entityName: 'asset_face_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_159,
_column_193,
_column_194,
_column_195,
_column_196,
_column_197,
_column_198,
_column_199,
_column_200,
_column_201,
_column_124,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape18 storeEntity = Shape18(
source: i0.VersionedTable(
entityName: 'store_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [_column_202, _column_203, _column_204],
attachedDatabase: database,
),
alias: null,
);
late final Shape47 trashedLocalAssetEntity = Shape47(
source: i0.VersionedTable(
entityName: 'trashed_local_asset_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id, album_id)'],
columns: [
_column_108,
_column_113,
_column_114,
_column_115,
_column_116,
_column_117,
_column_118,
_column_107,
_column_205,
_column_131,
_column_120,
_column_132,
_column_206,
_column_137,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape32 assetEditEntity = Shape32(
source: i0.VersionedTable(
entityName: 'asset_edit_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_159,
_column_207,
_column_208,
_column_209,
],
attachedDatabase: database,
),
alias: null,
);
late final Shape49 settings = Shape49(
source: i0.VersionedTable(
entityName: 'settings',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY("key")'],
columns: [_column_210, _column_224, _column_115],
attachedDatabase: database,
),
alias: null,
);
late final Shape51 assetOcrEntity = Shape51(
source: i0.VersionedTable(
entityName: 'asset_ocr_entity',
withoutRowId: true,
isStrict: true,
tableConstraints: ['PRIMARY KEY(id)'],
columns: [
_column_107,
_column_159,
_column_213,
_column_214,
_column_215,
_column_216,
_column_217,
_column_218,
_column_219,
_column_220,
_column_221,
_column_222,
_column_223,
_column_201,
],
attachedDatabase: database,
),
alias: null,
);
final i1.Index idxPartnerSharedWithId = i1.Index(
'idx_partner_shared_with_id',
'CREATE INDEX IF NOT EXISTS idx_partner_shared_with_id ON partner_entity (shared_with_id)',
);
final i1.Index idxLatLng = i1.Index(
'idx_lat_lng',
'CREATE INDEX IF NOT EXISTS idx_lat_lng ON remote_exif_entity (latitude, longitude)',
);
final i1.Index idxRemoteExifCity = i1.Index(
'idx_remote_exif_city',
'CREATE INDEX IF NOT EXISTS idx_remote_exif_city ON remote_exif_entity (city) WHERE city IS NOT NULL',
);
final i1.Index idxRemoteAlbumAssetAlbumAsset = i1.Index(
'idx_remote_album_asset_album_asset',
'CREATE INDEX IF NOT EXISTS idx_remote_album_asset_album_asset ON remote_album_asset_entity (album_id, asset_id)',
);
final i1.Index idxRemoteAssetCloudId = i1.Index(
'idx_remote_asset_cloud_id',
'CREATE INDEX IF NOT EXISTS idx_remote_asset_cloud_id ON remote_asset_cloud_id_entity (cloud_id)',
);
final i1.Index idxPersonOwnerId = i1.Index(
'idx_person_owner_id',
'CREATE INDEX IF NOT EXISTS idx_person_owner_id ON person_entity (owner_id)',
);
final i1.Index idxAssetFacePersonId = i1.Index(
'idx_asset_face_person_id',
'CREATE INDEX IF NOT EXISTS idx_asset_face_person_id ON asset_face_entity (person_id)',
);
final i1.Index idxAssetFaceAssetId = i1.Index(
'idx_asset_face_asset_id',
'CREATE INDEX IF NOT EXISTS idx_asset_face_asset_id ON asset_face_entity (asset_id)',
);
final i1.Index idxAssetFaceVisiblePerson = i1.Index(
'idx_asset_face_visible_person',
'CREATE INDEX IF NOT EXISTS idx_asset_face_visible_person ON asset_face_entity (person_id, asset_id) WHERE is_visible = 1 AND deleted_at IS NULL',
);
final i1.Index idxTrashedLocalAssetChecksum = i1.Index(
'idx_trashed_local_asset_checksum',
'CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_checksum ON trashed_local_asset_entity (checksum)',
);
final i1.Index idxTrashedLocalAssetAlbum = i1.Index(
'idx_trashed_local_asset_album',
'CREATE INDEX IF NOT EXISTS idx_trashed_local_asset_album ON trashed_local_asset_entity (album_id)',
);
final i1.Index idxAssetEditAssetId = i1.Index(
'idx_asset_edit_asset_id',
'CREATE INDEX IF NOT EXISTS idx_asset_edit_asset_id ON asset_edit_entity (asset_id)',
);
final i1.Index idxAssetOcrAssetId = i1.Index(
'idx_asset_ocr_asset_id',
'CREATE INDEX IF NOT EXISTS idx_asset_ocr_asset_id ON asset_ocr_entity (asset_id)',
);
}
i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema2 schema) from1To2,
required Future<void> Function(i1.Migrator m, Schema3 schema) from2To3,
@@ -16536,7 +15950,6 @@ i0.MigrationStepWithVersion migrationSteps({
required Future<void> Function(i1.Migrator m, Schema28 schema) from27To28,
required Future<void> Function(i1.Migrator m, Schema29 schema) from28To29,
required Future<void> Function(i1.Migrator m, Schema30 schema) from29To30,
required Future<void> Function(i1.Migrator m, Schema31 schema) from30To31,
}) {
return (currentVersion, database) async {
switch (currentVersion) {
@@ -16685,11 +16098,6 @@ i0.MigrationStepWithVersion migrationSteps({
final migrator = i1.Migrator(database, schema);
await from29To30(migrator, schema);
return 30;
case 30:
final schema = Schema31(database: database);
final migrator = i1.Migrator(database, schema);
await from30To31(migrator, schema);
return 31;
default:
throw ArgumentError.value('Unknown migration from $currentVersion');
}
@@ -16726,7 +16134,6 @@ i1.OnUpgrade stepByStep({
required Future<void> Function(i1.Migrator m, Schema28 schema) from27To28,
required Future<void> Function(i1.Migrator m, Schema29 schema) from28To29,
required Future<void> Function(i1.Migrator m, Schema30 schema) from29To30,
required Future<void> Function(i1.Migrator m, Schema31 schema) from30To31,
}) => i0.VersionedSchema.stepByStepHelper(
step: migrationSteps(
from1To2: from1To2,
@@ -16758,6 +16165,5 @@ i1.OnUpgrade stepByStep({
from27To28: from27To28,
from28To29: from28To29,
from29To30: from29To30,
from30To31: from30To31,
),
);
@@ -614,7 +614,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
return (
bucketSource: () => _watchRemoteBucket(filter: filter, groupBy: groupBy, sortBy: sortBy),
assetSource: (offset, count) =>
_getRemoteAssets(filter: filter, offset: offset, count: count, joinLocal: joinLocal, sortBy: sortBy),
_getRemoteAssets(filter: filter, offset: offset, count: count, joinLocal: joinLocal),
origin: origin,
);
}
@@ -651,7 +651,6 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
required int offset,
required int count,
bool joinLocal = false,
SortAssetsBy sortBy = SortAssetsBy.taken,
}) {
if (joinLocal) {
final query =
@@ -664,11 +663,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
])
..addColumns([_db.localAssetEntity.id])
..where(filter(_db.remoteAssetEntity))
..orderBy([
OrderingTerm.desc(
sortBy == SortAssetsBy.uploaded ? _db.remoteAssetEntity.uploadedAt : _db.remoteAssetEntity.createdAt,
),
])
..orderBy([OrderingTerm.desc(_db.remoteAssetEntity.createdAt)])
..limit(count, offset: offset);
return query
@@ -677,7 +672,7 @@ class DriftTimelineRepository extends DriftDatabaseRepository {
} else {
final query = _db.remoteAssetEntity.select()
..where(filter)
..orderBy([(row) => OrderingTerm.desc(sortBy == SortAssetsBy.uploaded ? row.uploadedAt : row.createdAt)])
..orderBy([(row) => OrderingTerm.desc(row.createdAt)])
..limit(count, offset: offset);
return query.map((row) => row.toDto()).get();
-4
View File
@@ -34,7 +34,6 @@ import 'schema_v27.dart' as v27;
import 'schema_v28.dart' as v28;
import 'schema_v29.dart' as v29;
import 'schema_v30.dart' as v30;
import 'schema_v31.dart' as v31;
class GeneratedHelper implements SchemaInstantiationHelper {
@override
@@ -100,8 +99,6 @@ class GeneratedHelper implements SchemaInstantiationHelper {
return v29.DatabaseAtV29(db);
case 30:
return v30.DatabaseAtV30(db);
case 31:
return v31.DatabaseAtV31(db);
default:
throw MissingSchemaException(version, versions);
}
@@ -138,6 +135,5 @@ class GeneratedHelper implements SchemaInstantiationHelper {
28,
29,
30,
31,
];
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -8,7 +8,7 @@
"format": "prettier --cache --check i18n/",
"format:fix": "prettier --cache --write --list-different i18n"
},
"packageManager": "pnpm@11.6.0",
"packageManager": "pnpm@11.9.0",
"engines": {
"pnpm": ">=10.0.0"
},
+1 -1
View File
@@ -13,5 +13,5 @@
"oidc-provider": "^9.0.0",
"tsx": "^4.20.6"
},
"packageManager": "pnpm@11.6.0"
"packageManager": "pnpm@11.9.0"
}
+1 -1
View File
@@ -27,7 +27,7 @@
"keywords": [],
"author": "",
"license": "GNU Affero General Public License version 3",
"packageManager": "pnpm@11.6.0",
"packageManager": "pnpm@11.9.0",
"devDependencies": {
"@extism/js-pdk": "^1.1.1",
"@immich/sdk": "workspace:*",
+1 -1
View File
@@ -32,5 +32,5 @@
"vite": "^8.0.16",
"vitest": "^4.1.8"
},
"packageManager": "pnpm@11.6.0"
"packageManager": "pnpm@11.9.0"
}
+2 -2
View File
@@ -84,7 +84,7 @@
"jose": "^6.0.0",
"js-yaml": "^4.1.0",
"jsonwebtoken": "^9.0.2",
"kysely": "0.28.17",
"kysely": "0.29.2",
"kysely-postgres-js": "^3.0.0",
"lodash": "^4.17.21",
"luxon": "^3.4.2",
@@ -116,7 +116,7 @@
"ua-parser-js": "^2.0.0",
"uuid": "^14.0.0",
"validator": "^13.12.0",
"zod": "4.3.6"
"zod": "4.4.3"
},
"devDependencies": {
"@eslint/js": "^10.0.0",
+2 -2
View File
@@ -76,7 +76,7 @@
"@koddsson/eslint-plugin-tscompat": "^0.2.0",
"@socket.io/component-emitter": "^3.1.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/enhanced-img": "^0.10.4",
"@sveltejs/enhanced-img": "^0.11.0",
"@sveltejs/kit": "^2.56.1",
"@sveltejs/vite-plugin-svelte": "7.1.2",
"@tailwindcss/vite": "^4.2.4",
@@ -105,7 +105,7 @@
"prettier-plugin-sort-json": "^4.1.1",
"prettier-plugin-svelte": "^4.0.0",
"rollup-plugin-visualizer": "^7.0.0",
"svelte": "5.56.3",
"svelte": "5.56.4",
"svelte-check": "^4.4.6",
"svelte-eslint-parser": "^1.3.3",
"tailwindcss": "^4.2.4",
@@ -15,12 +15,12 @@ import {
fromTimelinePlainDate,
fromTimelinePlainDateTime,
fromTimelinePlainYearMonth,
fromISODateTimeUTCToObject,
getTimes,
setDifference,
type TimelineDateTime,
type TimelineYearMonth,
getOrderingDate,
fromISODateTimeUTC,
} from '$lib/utils/timeline-util';
import { GroupInsertionCache } from './group-insertion-cache.svelte';
import { TimelineDay } from './timeline-day.svelte';
@@ -190,7 +190,7 @@ export class TimelineMonth {
isVideo: !bucketAssets.isImage[i],
livePhotoVideoId: bucketAssets.livePhotoVideoId[i],
localDateTime,
createdAt: fromISODateTimeUTC(bucketAssets.createdAt[i]).toLocal().toObject(),
createdAt: fromISODateTimeUTCToObject(bucketAssets.createdAt[i]),
fileCreatedAt,
ownerId: bucketAssets.ownerId[i],
projectionType: bucketAssets.projectionType[i],