diff --git a/bun.lockb b/bun.lockb
index 3449e97..5459b39 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/components/AppFileUpload.vue b/components/AppFileUpload.vue
index 997b254..a0fa024 100644
--- a/components/AppFileUpload.vue
+++ b/components/AppFileUpload.vue
@@ -15,6 +15,7 @@
 </template>
 
 <script setup lang="ts">
+import JSZip from 'jszip';
 import { UpdateGroupsRequest } from '~/server/api/update-artifact-groups.put';
 
 const releaseNotes = ref<string | null>(null)
@@ -25,8 +26,8 @@ const orgName = ref<string>('')
 const appName = ref<string>('')
 osType.value = dialogRef.value.data.osType
 prop.value = dialogRef.value.data.props
-orgName.value = dialogRef.value.data.orgName
-appName.value = dialogRef.value.data.appName
+orgName.value = dialogRef.value.data.props.orgName
+appName.value = dialogRef.value.data.props.appName
 
 const mimeTypeFromOsType = computed(() => getMimeTypeFromosType(osType.value ?? 'android'))
 const fileRef = ref<HTMLInputElement | null>(null)
@@ -96,6 +97,8 @@ const onUpload = async (file: File) => {
             releaseNotes: releaseNotes.value,
         },
     })
-    return data
+    return {
+        artifactId: data?.artifactId,
+    }
 };
 </script>
diff --git a/components/Releases.vue b/components/Releases.vue
index 5de890f..8b06198 100644
--- a/components/Releases.vue
+++ b/components/Releases.vue
@@ -47,7 +47,7 @@ const list = computed(() => data.value as any[])
 
 const dialog = useDialog();
 
-const osType = inject<OsType>('detail-app')
+const osType = inject<ComputedRef<OsType>>('detail-app')
 
 const upload = () => {
     dialog.open(AppFileUpload, {
@@ -58,8 +58,6 @@ const upload = () => {
         data: {
             osType,
             props,
-            orgName: props.orgName,
-            appName: props.appName,
         },
         onClose: (o) => {
             if (o?.data?.success) {
diff --git a/package.json b/package.json
index 4c69ac6..78b2875 100644
--- a/package.json
+++ b/package.json
@@ -21,11 +21,15 @@
     "@aws-sdk/s3-request-presigner": "^3.556.0",
     "@hebilicious/vue-query-nuxt": "^0.3.0",
     "@libsql/client": "^0.6.0",
+    "@plist/parse": "^1.1.0",
     "@tanstack/vue-query": "^5.28.9",
+    "@xmldom/xmldom": "^0.8.10",
+    "adbkit-apkreader": "^3.2.0",
     "chart.js": "3.3.2",
     "drizzle-orm": "^0.30.7",
     "h3": "^1.11.1",
     "jose": "^5.2.4",
+    "jszip": "^3.10.1",
     "lodash": "^4.17.21",
     "moment": "^2.30.1",
     "pg": "^8.11.3",
diff --git a/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue b/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue
index bd9a6f7..ba1fbae 100644
--- a/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue
+++ b/pages/orgs/[orgName]/apps/[appId]/[detailArtifact].vue
@@ -34,7 +34,7 @@
             <span class="font-semibold">File metadata</span>
             <div class="flex flex-col">
                 <label>{{ `MD5: ${detailArtifact?.fileMetadata?.md5?.replaceAll('"', '')}` }}</label>
-                <label>{{ `File Extension: ${getExtensionFromMimeType(detailArtifact?.fileMetadata?.contentType)}`
+                <label>{{ `File Extension: ${detailArtifact?.extension}`
                     }}</label>
                 <label>{{ `File Size: ${formatBytes(detailArtifact?.fileMetadata?.contentLength ?? 0)}` }}</label>
             </div>
diff --git a/pages/orgs/[orgName]/apps/[appId]/index.vue b/pages/orgs/[orgName]/apps/[appId]/index.vue
index 0c44892..63a8e7a 100644
--- a/pages/orgs/[orgName]/apps/[appId]/index.vue
+++ b/pages/orgs/[orgName]/apps/[appId]/index.vue
@@ -67,7 +67,9 @@ const detailApp = useFetch('/api/detail-app', {
         orgName: orgName,
     },
 })
-provide('detail-app', toOsType(detailApp.data.value?.osType))
+
+const osType = computed(() => toOsType(detailApp.data.value?.osType))
+provide('detail-app', osType)
 </script>
 
 <style>
diff --git a/server/api/artifacts/detail-artifact.get.ts b/server/api/artifacts/detail-artifact.get.ts
index 09795ae..35bdcd9 100644
--- a/server/api/artifacts/detail-artifact.get.ts
+++ b/server/api/artifacts/detail-artifact.get.ts
@@ -4,6 +4,7 @@ import { generateRandomPassword, getStorageKeys } from "~/server/utils/utils"
 import { takeUniqueOrThrow } from "../detail-app.get"
 import { GetObjectAttributesCommand, GetObjectTaggingCommand, HeadObjectCommand, ObjectAttributes } from "@aws-sdk/client-s3"
 import { S3AppClient, type AppHeadObjectCommandOutput } from "~/server/services/S3AppClient"
+import { readPackageFile } from "~/server/utils/package-reader"
 
 export default defineEventHandler(async (event) => {
     const db = event.context.drizzle
diff --git a/server/api/artifacts/download-artifact.get.ts b/server/api/artifacts/download-artifact.get.ts
index 3a2e76b..009f84a 100644
--- a/server/api/artifacts/download-artifact.get.ts
+++ b/server/api/artifacts/download-artifact.get.ts
@@ -36,7 +36,7 @@ export default defineEventHandler(async (event) => {
     const signedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({
         Bucket: s3BucketName,
         Key: assets,
-        ResponseContentDisposition: `attachment; filename ="${app.name}"`,
+        ResponseContentDisposition: `attachment; filename ="${app.name}${detailArtifact.extension ? `.${detailArtifact.extension}` : ''}"`,
     }), 1800)
     await sendRedirect(event, signedUrl)
 })
diff --git a/server/api/artifacts/upload-artifact-url.post.ts b/server/api/artifacts/upload-artifact-url.post.ts
index dcd73fc..634a911 100644
--- a/server/api/artifacts/upload-artifact-url.post.ts
+++ b/server/api/artifacts/upload-artifact-url.post.ts
@@ -2,7 +2,7 @@ import { and, eq } from "drizzle-orm"
 import { artifacts, organizations, organizationsPeople } from "~/server/db/schema"
 import { getStorageKeys, s3BucketName } from "~/server/utils/utils"
 import { takeUniqueOrThrow } from "../detail-app.get"
-import { CopyObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3"
+import { CopyObjectCommand, DeleteObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3"
 import { S3AppClient } from "~/server/services/S3AppClient"
 
 export default defineEventHandler(async (event) => {
@@ -21,6 +21,37 @@ export default defineEventHandler(async (event) => {
             return operators.and(operators.eq(fields.organizationsId, userOrg.organizationsId!), operators.eq(fields.name, appName!.toString()))
         },
     }).then(takeUniqueOrThrow)
+    const { temp, assets } = getStorageKeys(userOrg.organizationsId!, app.id, key)
+
+    // Processing the file
+    const s3 = new S3AppClient()
+    const tempSignedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({
+        Bucket: s3BucketName,
+        Key: temp,
+    }), 1800)
+    const response = await fetch(tempSignedUrl)
+    if (!response.ok) {
+        setResponseStatus(event, 400)
+        return
+    }
+    const arrayBuffer = await response.arrayBuffer() // WARNING: This will download to memory
+    const packageData = await readPackageFile(arrayBuffer)
+    if (!packageData) {
+        setResponseStatus(event, 400, 'Cannot read package')
+        return
+    }
+
+    await s3.copyObject(event, new CopyObjectCommand({
+        CopySource: `${s3BucketName}/${temp}`,
+        Bucket: s3BucketName,
+        Key: assets,
+    }))
+    await s3.deleteObject(event, new DeleteObjectCommand({
+        Bucket: s3BucketName,
+        Key: temp,
+    }))
+
+    // Inserting to db
     const lastArtifact = await db.query.artifacts.findFirst({
         orderBy(fields, operators) {
             return operators.desc(fields.releaseId)
@@ -37,23 +68,14 @@ export default defineEventHandler(async (event) => {
         createdAt: now,
         updatedAt: now,
         fileObjectKey: key,
-        versionCode2: '1',
-        versionName2: '1.0.0',
+        versionCode2: packageData?.versionCode?.toString()!,
+        versionName2: packageData?.versionName!,
         appsId: app.id,
         releaseNotes: releaseNotes,
         releaseId: newReleaseId,
+        extension: packageData?.extension,
+        packageName: packageData?.metadata?.packageName,
     })
-    const { temp, assets } = getStorageKeys(userOrg.organizationsId!, app.id, key)
-    const s3 = new S3AppClient()
-    await s3.copyObject(event, new CopyObjectCommand({
-        CopySource: `${s3BucketName}/${temp}`,
-        Bucket: s3BucketName,
-        Key: assets,
-    }))
-    await s3.deleteObject(event, new DeleteObjectCommand({
-        Bucket: s3BucketName,
-        Key: temp,
-    }))
 
     return {
         artifactId: artifactsId,
diff --git a/server/api/artifacts/upload-artifact.post.ts b/server/api/artifacts/upload-artifact.post.ts
index 652ca34..41a1029 100644
--- a/server/api/artifacts/upload-artifact.post.ts
+++ b/server/api/artifacts/upload-artifact.post.ts
@@ -25,15 +25,14 @@ export default defineEventHandler(async (event) => {
     }).then(takeUniqueOrThrow)
 
     const key = generateRandomPassword()
-    var expires = 300;
+    var expires = 500;
     const { temp } = getStorageKeys(userOrg.organizationsId!, app.id, key)
-    const limitUploadSizeMb = useRuntimeConfig(event)
     const s3 = new S3AppClient()
     const signedUrl = await s3.getSignedUrlPutObject(event, new PutObjectCommand({
         Bucket: s3BucketName,
         Key: temp,
-        ContentLength: limitUploadSizeMb.app.limitUploadSizeMb,
-    }), expires)    
+        // ContentLength: limitUploadSizeMb.app.limitUploadSizeMb,
+    }), expires)
     return {
         file: key,
         url: signedUrl,
diff --git a/server/api/install/download.get.ts b/server/api/install/download.get.ts
index 0209b39..73dd671 100644
--- a/server/api/install/download.get.ts
+++ b/server/api/install/download.get.ts
@@ -45,7 +45,7 @@ export default defineEventHandler(async (event) => {
     const signedUrl = await s3.getSignedUrlGetObject(event, new GetObjectCommand({
         Bucket: s3BucketName,
         Key: assets,
-        ResponseContentDisposition: `attachment; filename ="${app.name}"`
+        ResponseContentDisposition: `attachment; filename ="${app.name}${detailArtifact.extension ? `.${detailArtifact.extension}` : ''}"`,
     }), 1800)
     await sendRedirect(event, signedUrl)
 })
diff --git a/server/db/db.ts b/server/db/db.ts
index be2b51b..d85da27 100644
--- a/server/db/db.ts
+++ b/server/db/db.ts
@@ -5,5 +5,5 @@ import * as schema from '~/server/db/schema';
 const db = (env: any) => drizzle(createClient({
     url: env.DB_URL ?? env.NUXT_DB_URL,
     authToken: env.DB_AUTH_TOKEN ?? env.NUXT_DB_AUTH_TOKEN,
-}), { schema, logger: env.enableLogging ?? env.NUXT_APP_ENABLE_DRIZZLE_LOGGING ?? true });
+}), { schema, logger: env?.enableLogging ?? env?.NUXT_APP_ENABLE_DRIZZLE_LOGGING ?? true });
 export default db
diff --git a/server/db/drizzle/0010_jittery_warbird.sql b/server/db/drizzle/0010_jittery_warbird.sql
new file mode 100644
index 0000000..d1bc1a2
--- /dev/null
+++ b/server/db/drizzle/0010_jittery_warbird.sql
@@ -0,0 +1,2 @@
+ALTER TABLE artifacts ADD `extension` text;--> statement-breakpoint
+ALTER TABLE artifacts ADD `packageName` text;
\ No newline at end of file
diff --git a/server/db/drizzle/meta/0010_snapshot.json b/server/db/drizzle/meta/0010_snapshot.json
new file mode 100644
index 0000000..6e92e4f
--- /dev/null
+++ b/server/db/drizzle/meta/0010_snapshot.json
@@ -0,0 +1,472 @@
+{
+  "version": "5",
+  "dialect": "sqlite",
+  "id": "94c4da9d-02a6-4e6f-a819-4fa349ce7135",
+  "prevId": "6f8200da-3d28-490f-b7be-60d849d4fe2d",
+  "tables": {
+    "apps": {
+      "name": "apps",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "text",
+          "primaryKey": true,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "displayName": {
+          "name": "displayName",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "osType": {
+          "name": "osType",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "organizationsId": {
+          "name": "organizationsId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "apps_id_unique": {
+          "name": "apps_id_unique",
+          "columns": [
+            "id"
+          ],
+          "isUnique": true
+        },
+        "apps_organizationsId_name_unique": {
+          "name": "apps_organizationsId_name_unique",
+          "columns": [
+            "organizationsId",
+            "name"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {
+        "apps_organizationsId_organizations_id_fk": {
+          "name": "apps_organizationsId_organizations_id_fk",
+          "tableFrom": "apps",
+          "tableTo": "organizations",
+          "columnsFrom": [
+            "organizationsId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "artifacts": {
+      "name": "artifacts",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "text",
+          "primaryKey": true,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "fileObjectKey": {
+          "name": "fileObjectKey",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "versionName2": {
+          "name": "versionName2",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "versionCode2": {
+          "name": "versionCode2",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "releaseNotes": {
+          "name": "releaseNotes",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "createdAt": {
+          "name": "createdAt",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "updatedAt": {
+          "name": "updatedAt",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "releaseId": {
+          "name": "releaseId",
+          "type": "integer",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "extension": {
+          "name": "extension",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "packageName": {
+          "name": "packageName",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "appsId": {
+          "name": "appsId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "artifacts_id_unique": {
+          "name": "artifacts_id_unique",
+          "columns": [
+            "id"
+          ],
+          "isUnique": true
+        },
+        "artifacts_appsId_releaseId_unique": {
+          "name": "artifacts_appsId_releaseId_unique",
+          "columns": [
+            "appsId",
+            "releaseId"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {
+        "artifacts_appsId_apps_id_fk": {
+          "name": "artifacts_appsId_apps_id_fk",
+          "tableFrom": "artifacts",
+          "tableTo": "apps",
+          "columnsFrom": [
+            "appsId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "artifactsGroups": {
+      "name": "artifactsGroups",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "text",
+          "primaryKey": true,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "appsId": {
+          "name": "appsId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "publicId": {
+          "name": "publicId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "artifactsGroups_id_unique": {
+          "name": "artifactsGroups_id_unique",
+          "columns": [
+            "id"
+          ],
+          "isUnique": true
+        },
+        "artifactsGroups_publicId_unique": {
+          "name": "artifactsGroups_publicId_unique",
+          "columns": [
+            "publicId"
+          ],
+          "isUnique": true
+        },
+        "artifactsGroups_appsId_name_unique": {
+          "name": "artifactsGroups_appsId_name_unique",
+          "columns": [
+            "appsId",
+            "name"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {
+        "artifactsGroups_appsId_apps_id_fk": {
+          "name": "artifactsGroups_appsId_apps_id_fk",
+          "tableFrom": "artifactsGroups",
+          "tableTo": "apps",
+          "columnsFrom": [
+            "appsId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "artifactsGroupsManager": {
+      "name": "artifactsGroupsManager",
+      "columns": {
+        "artifactsId": {
+          "name": "artifactsId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "artifactsGroupsId": {
+          "name": "artifactsGroupsId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "artifactsGroupsManager_artifactsId_artifactsGroupsId_unique": {
+          "name": "artifactsGroupsManager_artifactsId_artifactsGroupsId_unique",
+          "columns": [
+            "artifactsId",
+            "artifactsGroupsId"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {
+        "artifactsGroupsManager_artifactsId_artifacts_id_fk": {
+          "name": "artifactsGroupsManager_artifactsId_artifacts_id_fk",
+          "tableFrom": "artifactsGroupsManager",
+          "tableTo": "artifacts",
+          "columnsFrom": [
+            "artifactsId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        },
+        "artifactsGroupsManager_artifactsGroupsId_artifactsGroups_id_fk": {
+          "name": "artifactsGroupsManager_artifactsGroupsId_artifactsGroups_id_fk",
+          "tableFrom": "artifactsGroupsManager",
+          "tableTo": "artifactsGroups",
+          "columnsFrom": [
+            "artifactsGroupsId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "organizations": {
+      "name": "organizations",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "text",
+          "primaryKey": true,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "displayName": {
+          "name": "displayName",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "organizations_id_unique": {
+          "name": "organizations_id_unique",
+          "columns": [
+            "id"
+          ],
+          "isUnique": true
+        },
+        "organizations_name_unique": {
+          "name": "organizations_name_unique",
+          "columns": [
+            "name"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "organizationsPeople": {
+      "name": "organizationsPeople",
+      "columns": {
+        "userId": {
+          "name": "userId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        },
+        "organizationId": {
+          "name": "organizationId",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": false,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "organizationsPeople_userId_organizationId_unique": {
+          "name": "organizationsPeople_userId_organizationId_unique",
+          "columns": [
+            "userId",
+            "organizationId"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {
+        "organizationsPeople_userId_users_id_fk": {
+          "name": "organizationsPeople_userId_users_id_fk",
+          "tableFrom": "organizationsPeople",
+          "tableTo": "users",
+          "columnsFrom": [
+            "userId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        },
+        "organizationsPeople_organizationId_organizations_id_fk": {
+          "name": "organizationsPeople_organizationId_organizations_id_fk",
+          "tableFrom": "organizationsPeople",
+          "tableTo": "organizations",
+          "columnsFrom": [
+            "organizationId"
+          ],
+          "columnsTo": [
+            "id"
+          ],
+          "onDelete": "no action",
+          "onUpdate": "no action"
+        }
+      },
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    },
+    "users": {
+      "name": "users",
+      "columns": {
+        "id": {
+          "name": "id",
+          "type": "text",
+          "primaryKey": true,
+          "notNull": true,
+          "autoincrement": false
+        },
+        "name": {
+          "name": "name",
+          "type": "text",
+          "primaryKey": false,
+          "notNull": true,
+          "autoincrement": false
+        }
+      },
+      "indexes": {
+        "users_id_unique": {
+          "name": "users_id_unique",
+          "columns": [
+            "id"
+          ],
+          "isUnique": true
+        }
+      },
+      "foreignKeys": {},
+      "compositePrimaryKeys": {},
+      "uniqueConstraints": {}
+    }
+  },
+  "enums": {},
+  "_meta": {
+    "schemas": {},
+    "tables": {},
+    "columns": {}
+  }
+}
\ No newline at end of file
diff --git a/server/db/drizzle/meta/_journal.json b/server/db/drizzle/meta/_journal.json
index 454acb2..6bc2fa8 100644
--- a/server/db/drizzle/meta/_journal.json
+++ b/server/db/drizzle/meta/_journal.json
@@ -71,6 +71,13 @@
       "when": 1714276274024,
       "tag": "0009_mighty_vargas",
       "breakpoints": true
+    },
+    {
+      "idx": 10,
+      "version": "5",
+      "when": 1714497020037,
+      "tag": "0010_jittery_warbird",
+      "breakpoints": true
     }
   ]
 }
\ No newline at end of file
diff --git a/server/db/schema.ts b/server/db/schema.ts
index e2ad68d..445eb43 100644
--- a/server/db/schema.ts
+++ b/server/db/schema.ts
@@ -76,6 +76,8 @@ export const artifacts = sqliteTable('artifacts', {
         mode: 'timestamp_ms',
     }),
     releaseId: integer('releaseId').notNull(),
+    extension: text('extension'),
+    packageName: text('packageName'),
 
     appsId: text('appsId').references(() => apps.id),
 }, t => ({
diff --git a/server/utils/package-reader.ts b/server/utils/package-reader.ts
new file mode 100644
index 0000000..42bd7c3
--- /dev/null
+++ b/server/utils/package-reader.ts
@@ -0,0 +1,61 @@
+import { parse } from "@plist/parse"
+import JSZip from "jszip"
+// @ts-ignore
+import ManifestParser from 'adbkit-apkreader/lib/apkreader/parser/manifest'
+
+export const readPackageFile = async (data: File | Buffer | ArrayBuffer | string | Blob) => {
+    var fileZip = new JSZip();
+    await fileZip.loadAsync(data)
+    var extension = ''
+    var packageMetadata: { versionCode: string, versionName: string, packageName: string } | undefined = undefined
+
+    // it's iOS
+    const appFolder = fileZip.folder('Payload')?.folder(/.app/).at(0)
+    if (appFolder) {
+        const infoPlistStr = await fileZip.folder(appFolder.name)?.file('Info.plist')?.async('arraybuffer')
+        const plist: any = parse(infoPlistStr!)
+        packageMetadata = {
+            versionName: plist.CFBundleShortVersionString,
+            versionCode: plist.CFBundleVersion,
+            packageName: plist.CFBundleIdentifier,
+        }
+        extension = 'ipa'
+    }
+
+    // it's android apk
+    const androidManifestApk = await fileZip.file('AndroidManifest.xml')?.async('nodebuffer')
+    if (androidManifestApk) {
+        extension = 'apk'
+        const manifestParser = new ManifestParser(androidManifestApk, {}).parse()
+        packageMetadata = {
+            versionCode: manifestParser.versionCode,
+            versionName: manifestParser.versionName,
+            packageName: manifestParser.packageName,
+        }
+    }
+
+    // it's android aab
+    const androidManifestAabString = await fileZip.folder('base/manifest')?.file('AndroidManifest.xml')?.async('binarystring')
+    if (androidManifestAabString) {
+        extension = 'aab'
+        const versionCode = androidManifestAabString.match(/versionCode.*?(?=\")/g)?.toString().replaceAll('versionCode\x1A\x02', '')
+        const versionName = androidManifestAabString.match(/versionName.*?(?=\()/g)?.toString().replaceAll('versionName\x1A\x05', '')
+        const packageName = androidManifestAabString.match(/package.*?(?=\")/g)?.toString().replaceAll('package\x1A\x13', '')
+        packageMetadata = {
+            versionCode: versionCode!,
+            versionName: versionName!,
+            packageName: packageName!,
+        }
+    }
+    if (!packageMetadata) {
+        return undefined
+    }
+
+    const packageDetail = {
+        versionName: packageMetadata?.versionName!,
+        versionCode: parseInt(packageMetadata?.versionCode!),
+        extension: extension,
+        metadata: packageMetadata,
+    }
+    return packageDetail
+}
diff --git a/utils/utils.ts b/utils/utils.ts
index ed6896d..1cd7e7c 100644
--- a/utils/utils.ts
+++ b/utils/utils.ts
@@ -50,4 +50,4 @@ export const formatDate = (value?: string | null) => {
 
 export const formatGroups = (groups: any[] | undefined) => {
     return groups && groups.length ? join(groups.map(e => e.artifactsGroups.name), ', ') : '-'
-}
+}
\ No newline at end of file