{"id":48763974,"url":"https://github.com/jonluca/react-native-photo-management","last_synced_at":"2026-04-13T07:44:38.616Z","repository":{"id":344502693,"uuid":"1181984098","full_name":"jonluca/react-native-photo-management","owner":"jonluca","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-15T01:45:49.000Z","size":1086,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-15T12:18:12.147Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jonluca.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-14T22:14:34.000Z","updated_at":"2026-03-15T01:45:52.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jonluca/react-native-photo-management","commit_stats":null,"previous_names":["jonluca/react-native-photo-management"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/jonluca/react-native-photo-management","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonluca%2Freact-native-photo-management","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonluca%2Freact-native-photo-management/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonluca%2Freact-native-photo-management/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonluca%2Freact-native-photo-management/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jonluca","download_url":"https://codeload.github.com/jonluca/react-native-photo-management/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jonluca%2Freact-native-photo-management/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31744404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T06:26:45.479Z","status":"ssl_error","status_checked_at":"2026-04-13T06:26:44.645Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-13T07:44:37.844Z","updated_at":"2026-04-13T07:44:38.610Z","avatar_url":"https://github.com/jonluca.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-native-photo-management\n\n`react-native-photo-management` is an Expo module for scanning the device photo library across projects.\n\nIt exposes:\n\n- iOS-native batch asset metadata lookup via PhotoKit\n- Android and iOS on-device image classification\n- Cross-platform food detection built on Apple Vision and ML Kit labels\n- Android JS fallback batching built on `expo-media-library`\n- A streaming `scanPhotoLibrary()` helper so app code owns persistence\n- Bulk album creation/update helpers that skip missing assets\n- Bulk asset delete helpers with missing-asset tolerance\n- A config plugin that wires `expo-media-library` permissions from a single plugin entry\n\n## Install\n\n```bash\nnpx expo install react-native-photo-management expo-media-library expo-device\n```\n\nAdd the plugin to your app config:\n\n```json\n{\n  \"expo\": {\n    \"plugins\": [\"react-native-photo-management\"]\n  }\n}\n```\n\nOptional plugin configuration:\n\n```json\n{\n  \"expo\": {\n    \"plugins\": [\n      [\n        \"react-native-photo-management\",\n        {\n          \"photosPermission\": \"Allow $(PRODUCT_NAME) to access your photos to scan and organize your library.\",\n          \"isAccessMediaLocationEnabled\": true\n        }\n      ]\n    ]\n  }\n}\n```\n\n## Platform Support\n\n| Platform | `getAssetInfoBatch`                  | `classifyImageBatch` | `detectFoodInImageBatch` | `createAlbumWithAssets` / `deleteAssetsBatch` | `scanPhotoLibrary`                |\n| -------- | ------------------------------------ | -------------------- | ------------------------ | --------------------------------------------- | --------------------------------- |\n| iOS      | Native batch bridge                  | Apple Vision         | Supported                | Supported                                     | Native batch metadata + streaming |\n| Android  | JS fallback via `expo-media-library` | ML Kit               | Supported                | Supported                                     | JS fallback + streaming           |\n| Web      | Unsupported                          | Unsupported          | Unsupported              | Unsupported                                   | Unsupported                       |\n\n## API\n\n### `isNativeBatchAssetInfoAvailable()`\n\nReturns `true` when the iOS native batch bridge is linked and available.\n\n### `isFoodDetectionAvailable()`\n\nReturns `true` on iOS and Android when the native image classifier is linked.\n\n### `requestPhotoLibraryPermission()`\n\nRequests photo-library access and resolves to `true` when access is granted.\n\n### `hasPhotoLibraryPermission()`\n\nChecks current photo-library access.\n\n### `countPhotoLibraryAssets(options?)`\n\nCounts assets for the requested media types. Defaults to photos and videos.\n\n### `getAssetInfoBatch(assetIds)`\n\nLoads `BatchAssetInfo[]` for a set of asset IDs.\n\n```ts\ntype BatchAssetInfo = {\n  id: string;\n  uri: string;\n  creationTime: number;\n  modificationTime: number;\n  width: number;\n  height: number;\n  mediaType: \"photo\" | \"video\" | \"audio\" | \"unknown\";\n  duration: number;\n  location: {\n    latitude: number;\n    longitude: number;\n    altitude?: number | null;\n    speed?: number | null;\n    heading?: number | null;\n  } | null;\n};\n```\n\nOn Android, unreadable or deleted assets are skipped.\n\n### `classifyImageBatch(assetIds, options?)`\n\nRuns on-device image labeling and returns platform-native labels.\n\n```ts\ntype ClassificationResult = {\n  assetId: string;\n  labels: Array\u003c{ label: string; confidence: number }\u003e;\n  error?: string;\n};\n```\n\nOn Android, non-photo assets are returned with an `error` instead of crashing the batch.\n\n### `detectFoodInImageBatch(assetIds, options?)`\n\nRuns on-device classification and filters for food-related labels.\n\n```ts\ntype FoodDetectionResult = {\n  assetId: string;\n  containsFood: boolean;\n  foodConfidence: number;\n  foodLabels: Array\u003c{ label: string; confidence: number }\u003e;\n  labels: Array\u003c{ label: string; confidence: number }\u003e;\n  error?: string;\n};\n```\n\nOn web, this throws an `UnsupportedPlatformError`.\n\nLabel vocabularies differ between Apple Vision and ML Kit, so the exact label text may not match across platforms even though the API contract does.\n\n### `createAlbumWithAssets(albumName, assetIds, options?)`\n\nCreates an album when missing or appends to an existing one. Missing or unreadable assets are skipped.\n\n```ts\ntype CreateAlbumWithAssetsResult = {\n  success: boolean;\n  albumId?: string;\n  albumName: string;\n  assetCount: number;\n  created: boolean;\n  skippedAssets: number;\n  missingAssetIds: string[];\n  error?: string;\n};\n```\n\n### `deleteAssetsBatch(assetIds)`\n\nDeletes all readable assets in a batch and reports any missing ones without failing the whole request.\n\n```ts\ntype DeleteAssetsBatchResult = {\n  requestedCount: number;\n  deletedCount: number;\n  skippedAssets: number;\n  missingAssetIds: string[];\n  success: boolean;\n  error?: string;\n};\n```\n\n### `scanPhotoLibrary(options)`\n\nStreams library assets in batches and reports progress after each page.\n\n```ts\nconst progress = await scanPhotoLibrary({\n  onBatch: async (assets) =\u003e {\n    // Persist or process assets here\n  },\n  onProgress: (value) =\u003e {\n    console.log(value.processedAssets, value.totalAssets);\n  },\n});\n```\n\n`scanPhotoLibrary()` returns:\n\n```ts\ntype ScanPhotoLibraryProgress = {\n  totalAssets: number;\n  processedAssets: number;\n  emittedAssets: number;\n  assetsWithLocation: number;\n  skippedAssets: number;\n  isComplete: boolean;\n  elapsedMs: number;\n  assetsPerSecond: number;\n  etaMs: number | null;\n  strategy: \"ios-native-batch\" | \"js-fallback\";\n  deviceTier: \"low\" | \"medium\" | \"high\";\n};\n```\n\n## Example\n\nThe repo includes an Expo example app in `example/App.tsx` that exercises:\n\n- permission checks\n- asset counting\n- streaming scan progress\n- batch metadata lookup\n- cross-platform image classification and food detection\n- bulk album creation from sampled assets\n\nRun it with:\n\n```bash\nnpm run example:start\nnpm run example:ios\nnpm run example:android\n```\n\n## Automated npm Publishing\n\nThis repo is configured for npm trusted publishing from GitHub Actions in `.github/workflows/publish.yml`.\n\nBefore the workflow can publish, configure the npm package once on npmjs.com:\n\n1. Open the package settings for `react-native-photo-management`.\n2. In `Trusted Publisher`, choose `GitHub Actions`.\n3. Set `Organization or user` to `jonluca`.\n4. Set `Repository` to `react-native-photo-management`.\n5. Set `Workflow filename` to `publish.yml`.\n\nnpm trusted publishing uses GitHub OIDC, so no `NPM_TOKEN` secret is required. Because this repo is public and the package is public, npm will automatically attach provenance attestations when the workflow publishes.\n\nAfter the first successful publish, npm recommends tightening package settings to `Require two-factor authentication and disallow tokens` so only trusted publishing remains available.\n\n## Release Flow\n\n1. Update `package.json` and `package-lock.json` to the next version.\n2. Commit the release.\n3. Push a matching Git tag such as `v0.1.1`.\n\nThe workflow publishes only when the pushed tag matches the `package.json` version exactly.\n\n## Manual Validation\n\nValidate the package contents before publishing:\n\n```bash\nnpm run build\nnpm run typecheck\nnpm run lint\nnpm test\nnpm pack\n```\n\nThen publish:\n\n```bash\nnpm publish --access public\n```\n\nManual local publishing is still available, but the intended release path is GitHub Actions trusted publishing via signed provenance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonluca%2Freact-native-photo-management","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonluca%2Freact-native-photo-management","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonluca%2Freact-native-photo-management/lists"}