diff --git a/.claude/skills/deep-code-review/SKILL.md b/.claude/skills/deep-code-review/SKILL.md index 985af903ca3381..1809047c4c0675 100644 --- a/.claude/skills/deep-code-review/SKILL.md +++ b/.claude/skills/deep-code-review/SKILL.md @@ -65,6 +65,7 @@ Evaluate the diff against the context gathered. Single checklist: - **Performance** - Unbounded growth? Blocking operations? - **Testing** - Coverage adequate? Happy path + edge cases + error cases? - **Breaking changes** - API contracts preserved? Migration needed? +- **Native ABI** (prebuilt Swift/Kotlin packages: `expo-modules-core`, `expo-modules-jsi`) - A change can be source-compatible but binary-incompatible: consumers prebuilt against the old artifact fail at link/load. Removing/renaming a `public`/`open` symbol? Moving a method into a protocol extension (remangles it)? Changing a signature/generics/`@available`, or a conformance that alters the `.swiftinterface`? Only real if the symbol is already released on the PR's target branch (exempt if it's new there); a PR targeting an `sdk-*` release branch is the riskiest case. A forwarding shim preserves the old symbol. If practically-exposed, flag it as a `critical` inline comment on the symbol and recommend the `breaking: ABI` label (suggest only — don't apply it). - **Stack coherence** (stacked PRs only) - Does the aggregate diff across the stack make sense as a whole? - **Adversarial examples** - Study the public API and any example code in the PR(s). Devise alternative examples that exercise edge cases, misuse the API, or pass unexpected inputs. Report any that produce bugs, crashes, or incorrect behavior. diff --git a/.github/workflows/android-unit-tests.yml b/.github/workflows/android-unit-tests.yml index d9f8a88bcb6aa9..8051d8be097947 100644 --- a/.github/workflows/android-unit-tests.yml +++ b/.github/workflows/android-unit-tests.yml @@ -62,6 +62,9 @@ jobs: run: echo "$(pwd)/bin" >> $GITHUB_PATH - name: 📦 Install node modules run: pnpm install --frozen-lockfile + - name: 💅 Run Spotless lint check + working-directory: apps/bare-expo/android + run: ./gradlew spotlessCheck || { echo '::error Spotless lint failed. Run `./gradlew spotlessApply` from `apps/bare-expo/android` to automatically fix formatting.' && exit 1; } - name: 🎸 Run native Android unit tests if: always() timeout-minutes: 30 diff --git a/.github/workflows/swift-format.yml b/.github/workflows/swift-format.yml index 12b78a6fc1ccf6..4ba1509717dea0 100644 --- a/.github/workflows/swift-format.yml +++ b/.github/workflows/swift-format.yml @@ -9,12 +9,16 @@ on: - .swift-format - scripts/swift-format.sh - packages/expo-modules-jsi/**/*.swift + - packages/expo-app-metrics/**/*.swift + - packages/expo-observe/**/*.swift pull_request: paths: - .github/workflows/swift-format.yml - .swift-format - scripts/swift-format.sh - packages/expo-modules-jsi/**/*.swift + - packages/expo-app-metrics/**/*.swift + - packages/expo-observe/**/*.swift concurrency: group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} @@ -70,3 +74,9 @@ jobs: - name: 🧹 Lint expo-modules-jsi run: ../../scripts/swift-format.sh --lint working-directory: packages/expo-modules-jsi + - name: 🧹 Lint expo-app-metrics + run: ../../scripts/swift-format.sh --lint + working-directory: packages/expo-app-metrics + - name: 🧹 Lint expo-observe + run: ../../scripts/swift-format.sh --lint + working-directory: packages/expo-observe diff --git a/apps/bare-expo/android/app/src/main/java/dev/expo/payments/MainApplication.kt b/apps/bare-expo/android/app/src/main/java/dev/expo/payments/MainApplication.kt index 635bb6e92ba681..856aed38a762f8 100644 --- a/apps/bare-expo/android/app/src/main/java/dev/expo/payments/MainApplication.kt +++ b/apps/bare-expo/android/app/src/main/java/dev/expo/payments/MainApplication.kt @@ -16,10 +16,10 @@ class MainApplication : Application(), ReactApplication { ExpoReactHostFactory.getDefaultReactHost( context = applicationContext, packageList = - expo.modules.benchmark.withBenchmarkingPackages(PackageList(this).packages).apply { - // Packages that cannot be autolinked yet can be added manually here, for example: - // add(MyReactNativePackage()) - } + expo.modules.benchmark.withBenchmarkingPackages(PackageList(this).packages).apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } ) } diff --git a/apps/bare-expo/ios/Podfile.lock b/apps/bare-expo/ios/Podfile.lock index aeabfd2a57ff48..81206e26be00a7 100644 --- a/apps/bare-expo/ios/Podfile.lock +++ b/apps/bare-expo/ios/Podfile.lock @@ -3017,7 +3017,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - RNGestureHandler (2.31.2): + - RNGestureHandler (2.32.0): - hermes-engine - RCTRequired - RCTTypeSafety @@ -3528,7 +3528,7 @@ DEPENDENCIES: - "RNCMaskedView (from `../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view`)" - "RNCPicker (from `../../../node_modules/.pnpm/@react-native-picker+picker@2.11.4_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-n_7aeabd3ff53aed0091871229c32b0005/node_modules/@react-native-picker/picker`)" - "RNDateTimePicker (from `../../../node_modules/.pnpm/@react-native-community+datetimepicker@8.6.0_expo@packages+expo_react-native@0.86.0-rc._9e80907fd85038827b6ad15fb6ad321d/node_modules/@react-native-community/datetimepicker`)" - - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler`)" + - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated`)" - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+j_1caf6d0de913e20dc62f3784cee8a325/node_modules/react-native-screens`)" - "RNSVG (from `../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest_8862e7d289ff7879e9d4b210ed280e3e/node_modules/react-native-svg`)" @@ -3989,7 +3989,7 @@ EXTERNAL SOURCES: RNDateTimePicker: :path: "../../../node_modules/.pnpm/@react-native-community+datetimepicker@8.6.0_expo@packages+expo_react-native@0.86.0-rc._9e80907fd85038827b6ad15fb6ad321d/node_modules/@react-native-community/datetimepicker" RNGestureHandler: - :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler" + :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler" RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated" RNScreens: @@ -4098,7 +4098,7 @@ SPEC CHECKSUMS: EXUpdates: c6488f0bebe92d6decb5f9b685d33ee91feeccf0 EXUpdatesInterface: 25408a97d682355eb9fb37e5aa6e22caece1881f FBLazyVector: 5466888598cde67aedb4d3a819adf471d1a3d8c9 - hermes-engine: 4c998771d5218e20701b63d8358199a520a54447 + hermes-engine: e355eb94d3f8b7f4c08531a4d42af958d36c13de libavif: 5f8e715bea24debec477006f21ef9e95432e254d libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 @@ -4193,7 +4193,7 @@ SPEC CHECKSUMS: RNCMaskedView: eb2b2e538afa907f05a5848a1a1ac26092e6fec9 RNCPicker: d74667bdfc08ed389a2a277d95b8faf2349290a9 RNDateTimePicker: b9e20c2a3af26f4ab10646359777205bbad1fdac - RNGestureHandler: 12ed45d9c6f0dada7bf9d1023769ad388fe7115d + RNGestureHandler: 92172e79df6e88e0e93b6341f9dcd8b5a02746ba RNReanimated: 71f76da8b61687f1cf225de572209c4968be1f5e RNScreens: 991cc417cd396602a6cf59a42139e5a9d91462a9 RNSVG: 3fe8590403ac9f107b4d14591bc6e54da4894e5c @@ -4209,6 +4209,6 @@ SPEC CHECKSUMS: Yoga: ebbcd9927b637646fb3b8704a6fe4d39f01ffced ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5 -PODFILE CHECKSUM: d14e340f2737af660bbf5d876247725a8672947a +PODFILE CHECKSUM: b229a566660aa43dca796561f23bd1ec6adce812 COCOAPODS: 1.16.2 diff --git a/apps/bare-expo/macrobenchmark/src/main/java/dev/expo/payments/macrobenchmark/StartupBenchmark.kt b/apps/bare-expo/macrobenchmark/src/main/java/dev/expo/payments/macrobenchmark/StartupBenchmark.kt index 79d8d411748306..7113766cf677d2 100644 --- a/apps/bare-expo/macrobenchmark/src/main/java/dev/expo/payments/macrobenchmark/StartupBenchmark.kt +++ b/apps/bare-expo/macrobenchmark/src/main/java/dev/expo/payments/macrobenchmark/StartupBenchmark.kt @@ -22,7 +22,7 @@ class StartupBenchmark { packageName = "dev.expo.payments", metrics = listOf(StartupTimingMetric()), iterations = 5, - startupMode = StartupMode.COLD, + startupMode = StartupMode.COLD ) { startActivityAndWait( Intent(Intent.ACTION_MAIN).apply { diff --git a/apps/bare-expo/package.json b/apps/bare-expo/package.json index 956f27c6970d9f..c6f14287eef7f6 100644 --- a/apps/bare-expo/package.json +++ b/apps/bare-expo/package.json @@ -84,7 +84,7 @@ "react": "^19.2.3", "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-keyboard-controller": "^1.21.9", "react-native-pager-view": "8.0.2", "react-native-reanimated": "4.3.1", diff --git a/apps/brownfield-tester/expo-app/package.json b/apps/brownfield-tester/expo-app/package.json index 03dffffbb7741c..a8cf634bf24119 100644 --- a/apps/brownfield-tester/expo-app/package.json +++ b/apps/brownfield-tester/expo-app/package.json @@ -31,7 +31,7 @@ "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-worklets": "0.8.3", "react-native-reanimated": "~4.3.1", "react-native-safe-area-context": "~5.6.2", diff --git a/apps/brownfield-tester/integrated/ios/Podfile.lock b/apps/brownfield-tester/integrated/ios/Podfile.lock index fffc4e0c4e5067..18fe810889d730 100644 --- a/apps/brownfield-tester/integrated/ios/Podfile.lock +++ b/apps/brownfield-tester/integrated/ios/Podfile.lock @@ -2087,7 +2087,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - RNGestureHandler (2.31.2): + - RNGestureHandler (2.32.0): - hermes-engine - RCTRequired - RCTTypeSafety @@ -2424,7 +2424,7 @@ DEPENDENCIES: - "ReactCommon/turbomodule/core (from `../../../../node_modules/.pnpm/react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest-preset@0.86.0-rc.3_@babe_fa57ac2619226ae98026112d284d2cba/node_modules/react-native/ReactCommon`)" - "ReactNativeDependencies (from `../../../../node_modules/.pnpm/react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest-preset@0.86.0-rc.3_@babe_fa57ac2619226ae98026112d284d2cba/node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)" - "RNCMaskedView (from `../../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view`)" - - "RNGestureHandler (from `../../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler`)" + - "RNGestureHandler (from `../../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated`)" - "RNScreens (from `../../../../node_modules/.pnpm/react-native-screens@4.25.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+j_1caf6d0de913e20dc62f3784cee8a325/node_modules/react-native-screens`)" - "RNWorklets (from `../../../../node_modules/.pnpm/react-native-worklets@0.8.3_patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89_14c70bd0e88f024ff3028384c1d4acce/node_modules/react-native-worklets`)" @@ -2647,7 +2647,7 @@ EXTERNAL SOURCES: RNCMaskedView: :path: "../../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view" RNGestureHandler: - :path: "../../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler" + :path: "../../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler" RNReanimated: :path: "../../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated" RNScreens: @@ -2675,9 +2675,9 @@ SPEC CHECKSUMS: ExpoKeepAwake: 359c47a1d9ccc3a3c519bca6e39562cce230c5bb ExpoLinking: 82458b046854a5802092a37a5228a8a228f928a4 ExpoLogBox: 7aa03244fe5eeced5129e4ec7ad5bd9a3994378e - ExpoModulesCore: 282743e45a8da9844fac713bdb14427d584b6d6e + ExpoModulesCore: 7ee5c9715b287b20ec9caa7f2577007597adf25a ExpoModulesJSI: f25a013ea9a79904bdd535e4bea0872e155cde09 - ExpoModulesWorklets: c755176116ae553ede2268ca6837c31eb4081f8a + ExpoModulesWorklets: 874ceeb92a8da1dfa32adf197aa65f926e74b9c5 ExpoModulesWorkletsAdapter: d39cf2fa668e1f8940cc0c65ef7c4e8566df2872 ExpoRouter: 06524ed53f9833aabf49053a119bcc92c1442098 ExpoSymbols: b3c964ddc1f1c8d8ddb0eeb830e3a8e42b77ed2d @@ -2763,7 +2763,7 @@ SPEC CHECKSUMS: ReactCommon: 99c616c9c4ab3119765aef7b190ee1fd850f29e7 ReactNativeDependencies: 433d597bb42b6198313fcee60a265d749e19468e RNCMaskedView: eb2b2e538afa907f05a5848a1a1ac26092e6fec9 - RNGestureHandler: 12ed45d9c6f0dada7bf9d1023769ad388fe7115d + RNGestureHandler: 92172e79df6e88e0e93b6341f9dcd8b5a02746ba RNReanimated: ee39e47dd4a63a6258b0e43526018bdbff00eb45 RNScreens: 991cc417cd396602a6cf59a42139e5a9d91462a9 RNWorklets: f8235564bb41484c62ddab7157139121f812f7ba diff --git a/apps/expo-go/ios/Podfile.lock b/apps/expo-go/ios/Podfile.lock index d98bf98cb24298..9da28e14b828b9 100644 --- a/apps/expo-go/ios/Podfile.lock +++ b/apps/expo-go/ios/Podfile.lock @@ -3623,7 +3623,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - RNGestureHandler (2.31.2): + - RNGestureHandler (2.32.0): - boost - DoubleConversion - fast_float @@ -4295,7 +4295,7 @@ DEPENDENCIES: - "RNCMaskedView (from `../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view`)" - "RNCPicker (from `../../../node_modules/.pnpm/@react-native-picker+picker@2.11.4_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-n_7aeabd3ff53aed0091871229c32b0005/node_modules/@react-native-picker/picker`)" - "RNDateTimePicker (from `../../../node_modules/.pnpm/@react-native-community+datetimepicker@9.1.0_expo@packages+expo_react-native@0.86.0-rc._62ff0edf26e6e75561f170036105235d/node_modules/@react-native-community/datetimepicker`)" - - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler`)" + - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated`)" - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+j_1caf6d0de913e20dc62f3784cee8a325/node_modules/react-native-screens`)" - "RNSVG (from `../../../node_modules/.pnpm/react-native-svg@15.15.4_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest_8862e7d289ff7879e9d4b210ed280e3e/node_modules/react-native-svg`)" @@ -4677,7 +4677,7 @@ EXTERNAL SOURCES: RNDateTimePicker: :path: "../../../node_modules/.pnpm/@react-native-community+datetimepicker@9.1.0_expo@packages+expo_react-native@0.86.0-rc._62ff0edf26e6e75561f170036105235d/node_modules/@react-native-community/datetimepicker" RNGestureHandler: - :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler" + :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler" RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated" RNScreens: @@ -4782,7 +4782,7 @@ SPEC CHECKSUMS: GoogleAppMeasurement: 8a82b93a6400c8e6551c0bcd66a9177f2e067aed GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 - hermes-engine: 42f0ed2cf70592b35e2ca49a6b725d31c8ad4136 + hermes-engine: d5c6d584ad5c5461ad9e34e0afb5d40d56e428f5 libavif: 5f8e715bea24debec477006f21ef9e95432e254d libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8 @@ -4880,7 +4880,7 @@ SPEC CHECKSUMS: RNCMaskedView: 5ef8c95cbab95334a32763b72896a7b7d07e6299 RNCPicker: bf95ec4b2483e2ab256047130bc536b437cd916c RNDateTimePicker: 73ffdd45f0ce1d00ff981031679a05206e619fdc - RNGestureHandler: 7d628c670dfcc1b9fa5840de5648b87ac0635362 + RNGestureHandler: 83e66307c200b98c746bd03113c4403da5c9b486 RNReanimated: c4e75786b152ca857d55fd2d1fc44ede67c79970 RNScreens: 9269ab4971b2bd24917be84295d2c2ae7d06e9be RNSVG: c6acd5c597d26625214295105756c5e488f5ae4c diff --git a/apps/expo-go/package.json b/apps/expo-go/package.json index d653cffd6cfea6..2b242f77751cf7 100644 --- a/apps/expo-go/package.json +++ b/apps/expo-go/package.json @@ -83,7 +83,7 @@ "lottie-react-native": "^7.3.8", "react": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-keyboard-controller": "^1.21.9", "react-native-maps": "1.27.2", "react-native-pager-view": "8.0.2", diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json index ca23bb0337c10a..fbb35bf4329838 100644 --- a/apps/native-component-list/package.json +++ b/apps/native-component-list/package.json @@ -148,7 +148,7 @@ "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", "react-native-dropdown-picker": "^5.3.0", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-keyboard-controller": "^1.21.9", "react-native-maps": "1.27.2", "react-native-pager-view": "8.0.2", diff --git a/apps/native-tests/ios/Podfile.lock b/apps/native-tests/ios/Podfile.lock index 5bb6deeec1c565..8d315f0368a294 100644 --- a/apps/native-tests/ios/Podfile.lock +++ b/apps/native-tests/ios/Podfile.lock @@ -435,6 +435,13 @@ PODS: - Nimble (~> 13.0.0) - Quick (~> 7.3.0) - React-hermes + - ExpoModulesWorklets (56.0.13): + - ExpoModulesCore + - ExpoModulesJSI + - ExpoModulesWorklets/Tests (56.0.13): + - ExpoModulesCore + - ExpoModulesJSI + - ExpoModulesTestCore - ExpoNotifications (56.0.14): - ExpoModulesCore - ExpoNotifications/Tests (56.0.14): @@ -2513,7 +2520,7 @@ PODS: - ReactCommon/turbomodule/core - ReactNativeDependencies - Yoga - - RNGestureHandler (2.31.2): + - RNGestureHandler (2.32.0): - hermes-engine - RCTRequired - RCTTypeSafety @@ -2779,6 +2786,8 @@ DEPENDENCIES: - ExpoModulesJSI (from `../../../packages/expo-modules-jsi/apple`) - ExpoModulesJSI/Tests (from `../../../packages/expo-modules-jsi/apple`) - ExpoModulesTestCore (from `../../../packages/expo-modules-test-core/ios`) + - ExpoModulesWorklets (from `../../../packages/expo-modules-core`) + - ExpoModulesWorklets/Tests (from `../../../packages/expo-modules-core`) - ExpoNotifications (from `../../../packages/expo-notifications/ios`) - ExpoNotifications/Tests (from `../../../packages/expo-notifications/ios`) - ExpoObserve (from `../../../packages/expo-observe/ios`) @@ -2869,7 +2878,7 @@ DEPENDENCIES: - "ReactCommon/turbomodule/core (from `../../../node_modules/.pnpm/react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest-preset@0.86.0-rc.3_@babe_fa57ac2619226ae98026112d284d2cba/node_modules/react-native/ReactCommon`)" - "ReactNativeDependencies (from `../../../node_modules/.pnpm/react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+jest-preset@0.86.0-rc.3_@babe_fa57ac2619226ae98026112d284d2cba/node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)" - "RNCMaskedView (from `../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view`)" - - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler`)" + - "RNGestureHandler (from `../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler`)" - "RNReanimated (from `../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated`)" - "RNScreens (from `../../../node_modules/.pnpm/react-native-screens@4.25.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-native+j_1caf6d0de913e20dc62f3784cee8a325/node_modules/react-native-screens`)" - "RNWorklets (from `../../../node_modules/.pnpm/react-native-worklets@0.8.3_patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89_14c70bd0e88f024ff3028384c1d4acce/node_modules/react-native-worklets`)" @@ -2934,6 +2943,9 @@ EXTERNAL SOURCES: :path: "../../../packages/expo-modules-jsi/apple" ExpoModulesTestCore: :path: "../../../packages/expo-modules-test-core/ios" + ExpoModulesWorklets: + inhibit_warnings: false + :path: "../../../packages/expo-modules-core" ExpoNotifications: inhibit_warnings: false :path: "../../../packages/expo-notifications/ios" @@ -3109,7 +3121,7 @@ EXTERNAL SOURCES: RNCMaskedView: :path: "../../../node_modules/.pnpm/@react-native-masked-view+masked-view@0.3.2_react-native@0.86.0-rc.3_@babel+core@7.29.0_b287539fe49ed5c16e1f5a35b43cdf77/node_modules/@react-native-masked-view/masked-view" RNGestureHandler: - :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.31.2_patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed737178_ae4bd3b9eacd55f76fcbeda380f2c6c2/node_modules/react-native-gesture-handler" + :path: "../../../node_modules/.pnpm/react-native-gesture-handler@2.32.0_react-native@0.86.0-rc.3_@babel+core@7.29.0_@react-_ca887e9234b849eb7759534fc37b34b6/node_modules/react-native-gesture-handler" RNReanimated: :path: "../../../node_modules/.pnpm/react-native-reanimated@4.3.1_patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8_63efc6dcd9f06abe16d862207d24882e/node_modules/react-native-reanimated" RNScreens: @@ -3135,9 +3147,10 @@ SPEC CHECKSUMS: ExpoClipboard: 40221903a1caa68259e022517af49d12962821fe ExpoImage: 3f44073bf450afdb87333f9671ffe7b9bfa5f70e ExpoMediaLibrary: 5ab82b8ace3f9ab7ac4ca3b2060bd915a4f1568f - ExpoModulesCore: 282743e45a8da9844fac713bdb14427d584b6d6e + ExpoModulesCore: 7ee5c9715b287b20ec9caa7f2577007597adf25a ExpoModulesJSI: f25a013ea9a79904bdd535e4bea0872e155cde09 ExpoModulesTestCore: 768a9a2b0401e87090bc7280cdb0607ab4cad382 + ExpoModulesWorklets: 874ceeb92a8da1dfa32adf197aa65f926e74b9c5 ExpoNotifications: 4f6324955cea640a65f40c67a8e42505a6a514b7 ExpoObserve: ebc1555f8538f65727dfe9208ae39a3111077d4f ExpoRouter: 06524ed53f9833aabf49053a119bcc92c1442098 @@ -3228,7 +3241,7 @@ SPEC CHECKSUMS: ReactCommon: 99c616c9c4ab3119765aef7b190ee1fd850f29e7 ReactNativeDependencies: 433d597bb42b6198313fcee60a265d749e19468e RNCMaskedView: eb2b2e538afa907f05a5848a1a1ac26092e6fec9 - RNGestureHandler: 12ed45d9c6f0dada7bf9d1023769ad388fe7115d + RNGestureHandler: 92172e79df6e88e0e93b6341f9dcd8b5a02746ba RNReanimated: 71f76da8b61687f1cf225de572209c4968be1f5e RNScreens: 991cc417cd396602a6cf59a42139e5a9d91462a9 RNWorklets: 948d670b3ad75fcdefb1c28ab0c6fb4d8af8e089 diff --git a/apps/notification-tester/package.json b/apps/notification-tester/package.json index 817ac60c2d8e58..2bad82373eed92 100644 --- a/apps/notification-tester/package.json +++ b/apps/notification-tester/package.json @@ -38,7 +38,7 @@ "native-component-list": "workspace:*", "test-suite": "workspace:*", "expo-task-manager": "workspace:*", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react": "19.2.3", "react-native": "0.86.0-rc.3", "react-native-reanimated": "4.3.0", diff --git a/apps/router-e2e/package.json b/apps/router-e2e/package.json index 5c61d929f6b270..f5933c256e697b 100644 --- a/apps/router-e2e/package.json +++ b/apps/router-e2e/package.json @@ -78,7 +78,7 @@ "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-pager-view": "^8.0.2", "react-native-safe-area-context": "5.7.0", "react-native-screens": "4.25.2", diff --git a/apps/test-suite/package.json b/apps/test-suite/package.json index 03c8fd31e88b3a..b675d15aa743e2 100644 --- a/apps/test-suite/package.json +++ b/apps/test-suite/package.json @@ -78,7 +78,7 @@ "path": "^0.12.7", "react": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-safe-area-context": "^5.6.2", "semver": "^7.7.4" }, diff --git a/docs/public/static/data/unversioned/expo-media-library-next.json b/docs/public/static/data/unversioned/expo-media-library-next.json index 91edd66d1e0099..3c2f9fe61696ac 100644 --- a/docs/public/static/data/unversioned/expo-media-library-next.json +++ b/docs/public/static/data/unversioned/expo-media-library-next.json @@ -1 +1 @@ -{"schemaVersion":"2.0","name":"expo-media-library-next","variant":"project","kind":1,"children":[{"name":"AssetField","variant":"declaration","kind":8,"children":[{"name":"CREATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"creationTime"}},{"name":"DURATION","variant":"declaration","kind":16,"type":{"type":"literal","value":"duration"}},{"name":"HEIGHT","variant":"declaration","kind":16,"type":{"type":"literal","value":"height"}},{"name":"MEDIA_TYPE","variant":"declaration","kind":16,"type":{"type":"literal","value":"mediaType"}},{"name":"MODIFICATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"modificationTime"}},{"name":"WIDTH","variant":"declaration","kind":16,"type":{"type":"literal","value":"width"}}]},{"name":"MediaSubtype","variant":"declaration","kind":8,"comment":{"summary":[{"kind":"text","text":"Describes specific variations of asset media. Maps to ["},{"kind":"code","text":"`PHAssetMediaSubtype`"},{"kind":"text","text":"](https://developer.apple.com/documentation/photokit/phassetmediasubtype)."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"children":[{"name":"DEPTH_EFFECT","variant":"declaration","kind":16,"type":{"type":"literal","value":"depthEffect"}},{"name":"HDR","variant":"declaration","kind":16,"type":{"type":"literal","value":"hdr"}},{"name":"HIGH_FRAME_RATE","variant":"declaration","kind":16,"type":{"type":"literal","value":"highFrameRate"}},{"name":"LIVE_PHOTO","variant":"declaration","kind":16,"type":{"type":"literal","value":"livePhoto"}},{"name":"PANORAMA","variant":"declaration","kind":16,"type":{"type":"literal","value":"panorama"}},{"name":"SCREENSHOT","variant":"declaration","kind":16,"type":{"type":"literal","value":"screenshot"}},{"name":"SPATIAL_MEDIA","variant":"declaration","kind":16,"type":{"type":"literal","value":"spatialMedia"}},{"name":"STREAM","variant":"declaration","kind":16,"type":{"type":"literal","value":"stream"}},{"name":"TIME_LAPSE","variant":"declaration","kind":16,"type":{"type":"literal","value":"timelapse"}},{"name":"VIDEO_CINEMATIC","variant":"declaration","kind":16,"type":{"type":"literal","value":"videoCinematic"}}]},{"name":"MediaType","variant":"declaration","kind":8,"children":[{"name":"AUDIO","variant":"declaration","kind":16,"type":{"type":"literal","value":"audio"}},{"name":"IMAGE","variant":"declaration","kind":16,"type":{"type":"literal","value":"image"}},{"name":"UNKNOWN","variant":"declaration","kind":16,"type":{"type":"literal","value":"unknown"}},{"name":"VIDEO","variant":"declaration","kind":16,"type":{"type":"literal","value":"video"}}]},{"name":"Album","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Album","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitialize an instance of an album with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unique identifier of the album."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Album","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Unique identifier of the album.\nCan be used to re-instantiate an "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" later."}]},"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.id"}},{"name":"add","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"add","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Adds one or more assets to the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been added."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///path/to/photo.png\");\nawait album.add(asset);\n```"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.add([asset1, asset2]);\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" or list of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" objects to add."}]},"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Permanently deletes the album from the device.\nOn Android, it deletes the album and all its assets.\nOn iOS, it deletes the album but keeps the assets in the main library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the deletion fails or the album could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"getAssets","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getAssets","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Retrieves all assets contained in the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nconsole.log(assets.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}},{"name":"getTitle","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getTitle","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the display title (name) of the album.\nNote that album titles are not guaranteed to be unique."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the album’s title string."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst title = await album.getTitle();\nconsole.log(title); // \"Camera\"\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}},{"name":"removeAssets","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"removeAssets","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Removes assets from the album without deleting them from the library.\nThis is supported only on iOS.\n\nOn Android, an asset can belong to only one album. To remove it from an album,\ndelete it or add it to another album."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been removed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nawait album.removeAssets(assets.slice(0, 2));\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" objects to remove from the album."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new album with a given name and assets.\nOn Android, if assets are provided and "},{"kind":"code","text":"`moveAssets`"},{"kind":"text","text":" is true, the assets will be moved into the new album. If false or not supported, the assets will be copied."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":"."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nconsole.log(await album.getTitle()); // \"My Album\"\n```"}]}]},"parameters":[{"name":"name","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the new album."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"assetsRefs","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"List of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" objects or file paths (file:///...) to include."}]},"type":{"type":"union","types":[{"type":"array","elementType":{"type":"intrinsic","name":"string"}},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}]}},{"name":"moveAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On Android, whether to move assets into the album. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple albums at once.\nOn Android, assets are always deleted along with the album regardless of "},{"kind":"code","text":"`deleteAssets`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the albums have been deleted."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nawait Album.delete([album]);\n```"}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}},{"name":"deleteAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On iOS, whether to delete the assets in the albums as well. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"get","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"get","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves an album by its title."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" if found, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.get(\"Camera\");\nif (album) {\n console.log(await album.getTitle()); // \"Camera\"\n}\n```"}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The title of the album to retrieve."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}},{"name":"getAll","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"getAll","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves all albums on the device."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await Album.getAll();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Album"},"name":"Album","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Album"}]},{"name":"Asset","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Asset","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitialize an instance of an asset with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"For Android, it is a "},{"kind":"code","text":"`contentUri`"},{"kind":"text","text":" (content://media/external/images/media/12345) and for iOS, it is "},{"kind":"code","text":"`PHAsset`"},{"kind":"text","text":" localIdentifier URI."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Asset","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"ID of the asset.\nCan be used to re-instantiate an "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" later.\nFor android it is a contentUri and PHAsset localIdentifier URI for iOS."}]},"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.id"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Deletes the asset from the device’s media store."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait asset.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}},{"name":"getAlbums","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getAlbums","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the albums containing this asset.\nOn Android, an asset is typically associated with a single album.\nOn iOS, an asset may belong to multiple albums."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" objects."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await asset.getAlbums();\nconsole.log(albums.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}},{"name":"getCreationTime","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getCreationTime","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the creation time of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the UNIX timestamp in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}},{"name":"getDuration","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getDuration","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the duration of the asset.\nApplies only to assets with media type "},{"kind":"inline-tag","tag":"@link","text":"MediaType.audio"},{"kind":"text","text":" or "},{"kind":"inline-tag","tag":"@link","text":"MediaType.video"},{"kind":"text","text":".\nFor other media types, it returns "},{"kind":"code","text":"`null`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the duration in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not applicable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}},{"name":"getExif","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getExif","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the exif data of the "},{"kind":"inline-tag","tag":"@link","text":"MediaType.image"},{"kind":"text","text":" asset.\nOn Android, this method requires the "},{"kind":"code","text":"`ACCESS_MEDIA_LOCATION`"},{"kind":"text","text":" permission to access location metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the exif data object or an empty object if the exif data is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}},{"name":"getFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"getFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is marked as a favorite.\nOn iOS, this checks if the asset is part of the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is a favorite, or "},{"kind":"code","text":"`false`"},{"kind":"text","text":" otherwise."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst isFavorite = await asset.getFavorite();\nconsole.log(isFavorite); // true or false\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}},{"name":"getFilename","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getFilename","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the filename of the asset, including its extension."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the filename string."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}},{"name":"getHeight","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getHeight","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the height of the asset in pixels.\nOnly applicable for image and video assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the height in pixels."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the filename cannot be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}},{"name":"getInfo","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getInfo","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets detailed information about the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an "},{"kind":"inline-tag","tag":"@link","text":"AssetInfo"}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}},{"name":"getIsInCloud","variant":"declaration","kind":2048,"signatures":[{"name":"getIsInCloud","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is stored in iCloud and not available locally.\nThis does not trigger a download of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is stored in iCloud and not available locally."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}},{"name":"getLivePhotoVideoUri","variant":"declaration","kind":2048,"signatures":[{"name":"getLivePhotoVideoUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the URI of the paired video for a Live Photo asset.\nThe video is extracted to a temporary file."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a "},{"kind":"code","text":"`file://`"},{"kind":"text","text":" URI string, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the asset is not a Live Photo."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}},{"name":"getLocation","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getLocation","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the location of the asset.\nOn Android, this method requires the "},{"kind":"code","text":"`ACCESS_MEDIA_LOCATION`"},{"kind":"text","text":" permission to access location metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the "},{"kind":"inline-tag","tag":"@link","text":"Location","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Location.ts","qualifiedName":"Location"}},{"kind":"text","text":" object or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the location data is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found, or if the permission is not granted on Android."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Location.ts","qualifiedName":"Location"},"name":"Location","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}},{"name":"getMediaSubtypes","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaSubtypes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of "},{"kind":"inline-tag","tag":"@link","text":"MediaSubtype"},{"kind":"text","text":" strings. Returns an empty array if no subtypes apply."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"MediaSubtype","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}},{"name":"getMediaType","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getMediaType","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the media type of the asset (image, video, audio or unknown)."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a "},{"kind":"inline-tag","tag":"@link","text":"MediaType"},{"kind":"text","text":" enum value."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"MediaType","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}},{"name":"getModificationTime","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getModificationTime","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the last modification time of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the UNIX timestamp in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}},{"name":"getOrientation","variant":"declaration","kind":2048,"signatures":[{"name":"getOrientation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the EXIF display orientation of the asset.\nOnly applicable for assets with media type "},{"kind":"inline-tag","tag":"@link","text":"MediaType.image"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a value between 1 and 8 as defined by the [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html), or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}},{"name":"getShape","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getShape","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the shape (width and height) of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the "},{"kind":"inline-tag","tag":"@link","text":"Shape","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Shape.ts","qualifiedName":"Shape"}},{"kind":"text","text":" object, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if any dimension is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Shape.ts","qualifiedName":"Shape"},"name":"Shape","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}},{"name":"getUri","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getUri","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the URI pointing to the asset’s location in the system.\nExample, for Android: "},{"kind":"code","text":"`file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the string URI."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}},{"name":"getWidth","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getWidth","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the width of the asset in pixels.\nOnly applicable for image and video assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the width in pixels."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}},{"name":"setFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"setFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Marks or unmarks the asset as a favorite. On iOS, this adds or removes the asset from the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the operation has completed."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait asset.setFavorite(true);\n```"}]}]},"parameters":[{"name":"isFavorite","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the asset should be marked as favorite."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new asset from a given file path.\nOptionally associates the asset with an album. On Android, if not specified, the asset will be placed in the default \"Pictures\" directory."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":"."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be created, for example, if the file does not exist or permission is denied."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg\");\nconsole.log(await asset.getFilename()); // \"IMG_20230915_123456.jpg\"\n```"}]}]},"parameters":[{"name":"filePath","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Local filesystem path (for example, "},{"kind":"code","text":"`file:///...`"},{"kind":"text","text":") of the file to import."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional "},{"kind":"inline-tag","tag":"@link","text":"Album"},{"kind":"text","text":" instance to place the asset in."}]},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple assets from the device's media store."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Asset"},"name":"Asset","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Asset"}]},{"name":"Query","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Query","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Initializes a new, empty query."}]},"type":{"type":"reference","name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}},{"name":"album","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"album","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets to only those contained in the specified album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The album to filter assets by."}]},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}},{"name":"eq","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"eq","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should equal. Each field has a specific unique type."}]},"type":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}},{"name":"exe","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"exe","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Executes the query and retrieves the matching assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves to an array of "},{"kind":"inline-tag","tag":"@link","text":"Asset"},{"kind":"text","text":" objects that match the query criteria."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await new Query()\n .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n .lte(AssetField.HEIGHT, 1080)\n .orderBy(AssetField.CREATION_TIME)\n .limit(20)\n .exe();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}},{"name":"gt","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"gt","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}},{"name":"gte","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"gte","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than or equal to the given value."}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}},{"name":"limit","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"limit","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Limits the number of results returned by the query."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The maximum number of results to return."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}},{"name":"lt","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"lt","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}},{"name":"lte","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"lte","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}},{"name":"offset","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"offset","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Skips the specified number of results."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"offset","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The number of results to skip."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}},{"name":"orderBy","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"orderBy","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Orders the results by the specified sort descriptor or asset field."}]},"parameters":[{"name":"sortDescriptors","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default."}]},"type":{"type":"union","types":[{"type":"reference","name":"AssetField","package":"expo-media-library"},{"type":"reference","name":"SortDescriptor","package":"expo-media-library"}]}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}},{"name":"within","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"within","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field's value is in the given array of values."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an "},{"kind":"inline-tag","tag":"@link","text":"AssetField"},{"kind":"text","text":" to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of values that the field should match. Each field has a specific unique type."}]},"type":{"type":"array","elementType":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Query"},"name":"Query","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Query"}]},{"name":"AssetFieldValueMap","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"AssetInfo","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"filename","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"id","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"isFavorite","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"uri","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"GranularPermission","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"audio"},{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"MediaLibraryAssetsChangeEvent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An event emitted when assets in the media library change."}]},"children":[{"name":"deletedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been deleted from the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"hasIncrementalChanges","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Whether the media library's changes can be described as incremental changes.\n"},{"kind":"code","text":"`true`"},{"kind":"text","text":" indicates the changes are described by the "},{"kind":"code","text":"`insertedAssets`"},{"kind":"text","text":", "},{"kind":"code","text":"`deletedAssets`"},{"kind":"text","text":" and\n"},{"kind":"code","text":"`updatedAssets`"},{"kind":"text","text":" values. "},{"kind":"code","text":"`false`"},{"kind":"text","text":" indicates that the scope of changes is too large and you\nshould perform a full assets reload.\nOn Android this is always "},{"kind":"code","text":"`false`"},{"kind":"text","text":" because the platform does not provide incremental change details."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"insertedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been inserted to the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"updatedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been updated.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}}]},{"name":"MediaTypeFilter","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"PermissionHookOptions","variant":"declaration","kind":2097152,"typeParameters":[{"name":"Options","variant":"typeParam","kind":131072,"type":{"type":"intrinsic","name":"object"}}],"type":{"type":"intersection","types":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"PermissionHookBehavior"},"name":"PermissionHookBehavior","package":"expo-modules-core"},{"type":"reference","name":"Options","package":"expo-modules-core","refersToTypeParameter":true}]}},{"name":"SortDescriptor","variant":"declaration","kind":2097152,"children":[{"name":"ascending","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"key","variant":"declaration","kind":1024,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}]},{"name":"usePermissions","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Check or request permissions to access the media library.\nThis uses both "},{"kind":"code","text":"`requestPermissionsAsync`"},{"kind":"text","text":" and "},{"kind":"code","text":"`getPermissionsAsync`"},{"kind":"text","text":" to interact with the permissions."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n writeOnly: true,\n granularPermissions: ['photo'],\n});\n```"}]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"granularPermissions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}},{"name":"writeOnly","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}],"name":"PermissionHookOptions","package":"expo-modules-core"}}],"type":{"type":"tuple","elements":[{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionResponse"},"name":"PermissionResponse","package":"expo-modules-core"},{"type":"literal","value":null}]},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"RequestPermissionMethod"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionResponse"},"name":"PermissionResponse","package":"expo-modules-core"}],"name":"RequestPermissionMethod","package":"expo-modules-core"},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"GetPermissionMethod"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionResponse"},"name":"PermissionResponse","package":"expo-modules-core"}],"name":"GetPermissionMethod","package":"expo-modules-core"}]}}]}},"defaultValue":"..."},{"name":"addListener","variant":"declaration","kind":64,"signatures":[{"name":"addListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Subscribes for updates in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"An ["},{"kind":"code","text":"`EventSubscription`"},{"kind":"text","text":"](#eventsubscription) object that you can call "},{"kind":"code","text":"`remove()`"},{"kind":"text","text":" on when\nyou would like to unsubscribe the listener."}]}]},"parameters":[{"name":"listener","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A callback that is fired when any assets have been inserted or deleted from the\nlibrary. On Android it's invoked with an empty object. On iOS it's invoked with\n["},{"kind":"code","text":"`MediaLibraryAssetsChangeEvent`"},{"kind":"text","text":"](#medialibraryassetschangeevent) object."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reference","name":"MediaLibraryAssetsChangeEvent","package":"expo-media-library"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/EventEmitter.ts","qualifiedName":"EventSubscription"},"name":"EventSubscription","package":"expo-modules-core"}}]},{"name":"getPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Checks user's permissions for accessing media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to check write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has\nan effect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionResponse"},"name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPicker","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPicker","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows the user to update the assets that your app has access to.\nThe system modal is only displayed if the user originally allowed only "},{"kind":"code","text":"`limited`"},{"kind":"text","text":" access to their\nmedia library, otherwise this method is a no-op."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that either rejects if the method is unavailable, or resolves to "},{"kind":"code","text":"`void`"},{"kind":"text","text":".\n> __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\nThat information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using ["},{"kind":"code","text":"`addListener()`"},{"kind":"text","text":"](#medialibraryaddlistenerlistener).\nIf "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`false`"},{"kind":"text","text":", the user changed their permissions."}]},{"tag":"@platform","content":[{"kind":"text","text":"android 14+"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented."}]},"type":{"type":"array","elementType":{"type":"reference","name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"removeAllListeners","variant":"declaration","kind":64,"signatures":[{"name":"removeAllListeners","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes all listeners."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"requestPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"requestPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks the user to grant permissions for accessing media in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to request write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has an\neffect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions.\n\n> When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionResponse"},"name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]}],"packageName":"expo-media-library"} \ No newline at end of file +{"schemaVersion":"2.0","name":"expo-media-library-next","variant":"project","kind":1,"children":[{"name":"AssetField","variant":"declaration","kind":8,"children":[{"name":"CREATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"creationTime"}},{"name":"DURATION","variant":"declaration","kind":16,"type":{"type":"literal","value":"duration"}},{"name":"HEIGHT","variant":"declaration","kind":16,"type":{"type":"literal","value":"height"}},{"name":"MEDIA_TYPE","variant":"declaration","kind":16,"type":{"type":"literal","value":"mediaType"}},{"name":"MODIFICATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"modificationTime"}},{"name":"WIDTH","variant":"declaration","kind":16,"type":{"type":"literal","value":"width"}}]},{"name":"MediaSubtype","variant":"declaration","kind":8,"comment":{"summary":[{"kind":"text","text":"Describes specific variations of asset media. Maps to ["},{"kind":"code","text":"`PHAssetMediaSubtype`"},{"kind":"text","text":"](https://developer.apple.com/documentation/photokit/phassetmediasubtype)."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"children":[{"name":"DEPTH_EFFECT","variant":"declaration","kind":16,"type":{"type":"literal","value":"depthEffect"}},{"name":"HDR","variant":"declaration","kind":16,"type":{"type":"literal","value":"hdr"}},{"name":"HIGH_FRAME_RATE","variant":"declaration","kind":16,"type":{"type":"literal","value":"highFrameRate"}},{"name":"LIVE_PHOTO","variant":"declaration","kind":16,"type":{"type":"literal","value":"livePhoto"}},{"name":"PANORAMA","variant":"declaration","kind":16,"type":{"type":"literal","value":"panorama"}},{"name":"SCREENSHOT","variant":"declaration","kind":16,"type":{"type":"literal","value":"screenshot"}},{"name":"SPATIAL_MEDIA","variant":"declaration","kind":16,"type":{"type":"literal","value":"spatialMedia"}},{"name":"STREAM","variant":"declaration","kind":16,"type":{"type":"literal","value":"stream"}},{"name":"TIME_LAPSE","variant":"declaration","kind":16,"type":{"type":"literal","value":"timelapse"}},{"name":"VIDEO_CINEMATIC","variant":"declaration","kind":16,"type":{"type":"literal","value":"videoCinematic"}}]},{"name":"MediaType","variant":"declaration","kind":8,"children":[{"name":"AUDIO","variant":"declaration","kind":16,"type":{"type":"literal","value":"audio"}},{"name":"IMAGE","variant":"declaration","kind":16,"type":{"type":"literal","value":"image"}},{"name":"UNKNOWN","variant":"declaration","kind":16,"type":{"type":"literal","value":"unknown"}},{"name":"VIDEO","variant":"declaration","kind":16,"type":{"type":"literal","value":"video"}}]},{"name":"PermissionStatus","variant":"declaration","kind":8,"children":[{"name":"DENIED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has denied the permission."}]},"type":{"type":"literal","value":"denied"}},{"name":"GRANTED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has granted the permission."}]},"type":{"type":"literal","value":"granted"}},{"name":"UNDETERMINED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User hasn't granted or denied the permission yet."}]},"type":{"type":"literal","value":"undetermined"}}]},{"name":"Album","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a media album (collection of assets) on the device.\n\nAn ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) groups together media assets (images, videos, or audio files).\nTo create a new album, use "},{"kind":"code","text":"`Album.create()`"},{"kind":"text","text":".\nTo fetch an existing album, use "},{"kind":"code","text":"`Album.get()`"},{"kind":"text","text":"."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Album","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitializes an instance of an album with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unique identifier of the album."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Album","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Unique identifier of the album.\nCan be used to re-instantiate an ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) later."}]},"type":{"type":"intrinsic","name":"string"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.id"}},{"name":"add","variant":"declaration","kind":2048,"signatures":[{"name":"add","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds one or more assets to the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been added."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///path/to/photo.png\");\nawait album.add(asset);\n```"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.add([asset1, asset2]);\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) or list of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects to add."}]},"type":{"type":"union","types":[{"type":"reference","name":"Asset","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}},{"name":"delete","variant":"declaration","kind":2048,"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Permanently deletes the album from the device.\nOn Android, it deletes the album and all its assets.\nOn iOS, it deletes the album but keeps the assets in the main library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the deletion fails or the album could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"getAssets","variant":"declaration","kind":2048,"signatures":[{"name":"getAssets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Retrieves all assets contained in the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nconsole.log(assets.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}},{"name":"getTitle","variant":"declaration","kind":2048,"signatures":[{"name":"getTitle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the display title (name) of the album.\nNote that album titles are not guaranteed to be unique."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the album's title string."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst title = await album.getTitle();\nconsole.log(title); // \"Camera\"\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}},{"name":"removeAssets","variant":"declaration","kind":2048,"signatures":[{"name":"removeAssets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes assets from the album without deleting them from the library.\nThis is supported only on iOS.\n\nOn Android, an asset can belong to only one album. To remove it from an album,\ndelete it or add it to another album."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been removed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nawait album.removeAssets(assets.slice(0, 2));\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects to remove from the album."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new album with a given name and assets.\nOn Android, if assets are provided and "},{"kind":"code","text":"`moveAssets`"},{"kind":"text","text":" is true, the assets will be moved into the new album. If false or not supported, the assets will be copied."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album)."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nconsole.log(await album.getTitle()); // \"My Album\"\n```"}]}]},"parameters":[{"name":"name","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the new album."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"assetsRefs","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"List of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects or file paths (file:///...) to include."}]},"type":{"type":"union","types":[{"type":"array","elementType":{"type":"intrinsic","name":"string"}},{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}]}},{"name":"moveAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On Android, whether to move assets into the album. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple albums at once.\nOn Android, assets are always deleted along with the album regardless of "},{"kind":"code","text":"`deleteAssets`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the albums have been deleted."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nawait Album.delete([album]);\n```"}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}},{"name":"deleteAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On iOS, whether to delete the assets in the albums as well. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"get","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"get","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves an album by its title."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) if found, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.get(\"Camera\");\nif (album) {\n console.log(await album.getTitle()); // \"Camera\"\n}\n```"}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The title of the album to retrieve."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Album","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}},{"name":"getAll","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"getAll","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves all albums on the device."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await Album.getAll();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Album"},"name":"Album","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Album"}]},{"name":"Asset","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a media asset in the device media library."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Asset","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitializes an instance of an asset with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The asset identifier. On Android, this is a "},{"kind":"code","text":"`content://`"},{"kind":"text","text":" URI. On iOS, this is a "},{"kind":"code","text":"`PHAsset`"},{"kind":"text","text":" local identifier URI."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Asset","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Asset identifier.\nCan be used to re-instantiate an ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) later."}]},"type":{"type":"intrinsic","name":"string"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.id"}},{"name":"delete","variant":"declaration","kind":2048,"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Deletes the asset from the media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving once the deletion has completed."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}},{"name":"getAlbums","variant":"declaration","kind":2048,"signatures":[{"name":"getAlbums","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets albums that contain the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) objects."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}},{"name":"getCreationTime","variant":"declaration","kind":2048,"signatures":[{"name":"getCreationTime","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset creation time."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a timestamp in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}},{"name":"getDuration","variant":"declaration","kind":2048,"signatures":[{"name":"getDuration","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset duration."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the duration in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}},{"name":"getExif","variant":"declaration","kind":2048,"signatures":[{"name":"getExif","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset EXIF metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a map of EXIF tags."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}},{"name":"getFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"getFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is marked as a favorite.\nOn iOS, this checks if the asset is part of the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is marked as favorite, otherwise "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}},{"name":"getFilename","variant":"declaration","kind":2048,"signatures":[{"name":"getFilename","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset filename."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset filename."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}},{"name":"getHeight","variant":"declaration","kind":2048,"signatures":[{"name":"getHeight","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset height."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset height in pixels."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}},{"name":"getInfo","variant":"declaration","kind":2048,"signatures":[{"name":"getInfo","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets complete information about the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an ["},{"kind":"code","text":"`AssetInfo`"},{"kind":"text","text":"](#assetinfo) object."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}},{"name":"getIsInCloud","variant":"declaration","kind":2048,"signatures":[{"name":"getIsInCloud","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is stored in iCloud and not available locally.\nThis does not trigger a download of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is stored in iCloud and unavailable locally, otherwise "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}},{"name":"getLivePhotoVideoUri","variant":"declaration","kind":2048,"signatures":[{"name":"getLivePhotoVideoUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the URI of the paired video for a Live Photo asset.\nThe video is extracted to a temporary file."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the paired video URI, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the asset is not a Live Photo or no paired video is available."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}},{"name":"getLocation","variant":"declaration","kind":2048,"signatures":[{"name":"getLocation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset location."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset location, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when location is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Location","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}},{"name":"getMediaSubtypes","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaSubtypes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`MediaSubtype`"},{"kind":"text","text":"](#mediasubtype) values."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"MediaSubtype","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}},{"name":"getMediaType","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset media type."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset media type."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"MediaType","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}},{"name":"getModificationTime","variant":"declaration","kind":2048,"signatures":[{"name":"getModificationTime","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset modification time."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a timestamp in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}},{"name":"getOrientation","variant":"declaration","kind":2048,"signatures":[{"name":"getOrientation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the EXIF display orientation of the asset.\nOnly applicable for assets with media type "},{"kind":"code","text":"`MediaType.IMAGE`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the EXIF orientation value, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when unavailable."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}},{"name":"getShape","variant":"declaration","kind":2048,"signatures":[{"name":"getShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset dimensions."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset shape, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Shape","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}},{"name":"getUri","variant":"declaration","kind":2048,"signatures":[{"name":"getUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset URI."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset URI."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}},{"name":"getWidth","variant":"declaration","kind":2048,"signatures":[{"name":"getWidth","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset width."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset width in pixels."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}},{"name":"setFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"setFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Marks or unmarks the asset as a favorite. On iOS, this adds or removes the asset from the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the favorite state has been updated."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"isFavorite","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the asset should be marked as favorite."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Creates an asset from a local file path."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset)."}]}]},"parameters":[{"name":"filePath","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Local file URI of the asset to create."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional album to add the created asset to."}]},"type":{"type":"reference","name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Deletes multiple assets from the media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving once deletion has completed."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Assets to delete."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Asset"},"name":"Asset","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Asset"}]},{"name":"Query","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a query to fetch data from the media library.\n\nA "},{"kind":"code","text":"`query`"},{"kind":"text","text":" implements a builder pattern, allowing you to chain multiple filtering and sorting methods\nto construct complex queries."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Query","variant":"signature","kind":16384,"type":{"type":"reference","name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}},{"name":"album","variant":"declaration","kind":2048,"signatures":[{"name":"album","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets to only those contained in the specified album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The album to filter assets by."}]},"type":{"type":"reference","name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}},{"name":"eq","variant":"declaration","kind":2048,"signatures":[{"name":"eq","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should equal. Each field has a specific unique type."}]},"type":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}},{"name":"exe","variant":"declaration","kind":2048,"signatures":[{"name":"exe","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes the query and retrieves the matching assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves to an array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects that match the query criteria."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await new Query()\n .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n .lte(AssetField.HEIGHT, 1080)\n .orderBy(AssetField.CREATION_TIME)\n .limit(20)\n .exe();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}},{"name":"gt","variant":"declaration","kind":2048,"signatures":[{"name":"gt","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}},{"name":"gte","variant":"declaration","kind":2048,"signatures":[{"name":"gte","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}},{"name":"limit","variant":"declaration","kind":2048,"signatures":[{"name":"limit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Limits the number of results returned by the query."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The maximum number of results to return."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}},{"name":"lt","variant":"declaration","kind":2048,"signatures":[{"name":"lt","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}},{"name":"lte","variant":"declaration","kind":2048,"signatures":[{"name":"lte","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}},{"name":"offset","variant":"declaration","kind":2048,"signatures":[{"name":"offset","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Skips the specified number of results."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"offset","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The number of results to skip."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}},{"name":"orderBy","variant":"declaration","kind":2048,"signatures":[{"name":"orderBy","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Orders the results by the specified sort descriptor or asset field."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"sortDescriptors","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default."}]},"type":{"type":"union","types":[{"type":"reference","name":"AssetField","package":"expo-media-library"},{"type":"reference","name":"SortDescriptor","package":"expo-media-library"}]}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}},{"name":"within","variant":"declaration","kind":2048,"signatures":[{"name":"within","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field's value is in the given array of values."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of values that the field should match. Each field has a specific unique type."}]},"type":{"type":"array","elementType":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Query"},"name":"Query","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Query"}]},{"name":"EventSubscription","variant":"declaration","kind":256,"comment":{"summary":[{"kind":"text","text":"A subscription object that allows to conveniently remove an event listener from the emitter."}]},"children":[{"name":"remove","variant":"declaration","kind":2048,"signatures":[{"name":"remove","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes an event listener for which the subscription has been created.\nAfter calling this function, the listener will no longer receive any events from the emitter."}]},"type":{"type":"intrinsic","name":"void"}}]}]},{"name":"AssetFieldValueMap","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"AssetInfo","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"filename","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"id","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"isFavorite","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"uri","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"GranularPermission","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"audio"},{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"Location","variant":"declaration","kind":2097152,"children":[{"name":"latitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"longitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"MediaLibraryAssetsChangeEvent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An event emitted when assets in the media library change."}]},"children":[{"name":"deletedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been deleted from the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"hasIncrementalChanges","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Whether the media library's changes can be described as incremental changes.\n"},{"kind":"code","text":"`true`"},{"kind":"text","text":" indicates the changes are described by the "},{"kind":"code","text":"`insertedAssets`"},{"kind":"text","text":", "},{"kind":"code","text":"`deletedAssets`"},{"kind":"text","text":" and\n"},{"kind":"code","text":"`updatedAssets`"},{"kind":"text","text":" values. "},{"kind":"code","text":"`false`"},{"kind":"text","text":" indicates that the scope of changes is too large and you\nshould perform a full assets reload.\nOn Android this is always "},{"kind":"code","text":"`false`"},{"kind":"text","text":" because the platform does not provide incremental change details."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"insertedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been inserted to the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"updatedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been updated.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}}]},{"name":"MediaTypeFilter","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"PermissionExpiration","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Permission expiration time. Currently, all permissions are granted permanently."}]},"type":{"type":"union","types":[{"type":"literal","value":"never"},{"type":"intrinsic","name":"number"}]}},{"name":"PermissionHookOptions","variant":"declaration","kind":2097152,"typeParameters":[{"name":"Options","variant":"typeParam","kind":131072,"type":{"type":"intrinsic","name":"object"}}],"type":{"type":"intersection","types":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"PermissionHookBehavior"},"name":"PermissionHookBehavior","package":"expo-modules-core"},{"type":"reference","name":"Options","package":"expo-modules-core","refersToTypeParameter":true}]}},{"name":"PermissionResponse","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An object obtained by permissions get and request functions."}]},"children":[{"name":"canAskAgain","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Indicates if user can be asked again for specific permission.\nIf not, one should be directed to the Settings app\nin order to enable/disable the permission."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"expires","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines time when the permission expires."}]},"type":{"type":"reference","name":"PermissionExpiration","package":"expo-modules-core"}},{"name":"granted","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"A convenience boolean that indicates if the permission is granted."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"status","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines the status of the permission."}]},"type":{"type":"reference","name":"PermissionStatus","package":"expo-modules-core"}}]},{"name":"Shape","variant":"declaration","kind":2097152,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"SortDescriptor","variant":"declaration","kind":2097152,"children":[{"name":"ascending","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"key","variant":"declaration","kind":1024,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}]},{"name":"usePermissions","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Check or request permissions to access the media library.\nThis uses both "},{"kind":"code","text":"`requestPermissionsAsync`"},{"kind":"text","text":" and "},{"kind":"code","text":"`getPermissionsAsync`"},{"kind":"text","text":" to interact with the permissions."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n writeOnly: true,\n granularPermissions: ['photo'],\n});\n```"}]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"granularPermissions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}},{"name":"writeOnly","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}],"name":"PermissionHookOptions","package":"expo-modules-core"}}],"type":{"type":"tuple","elements":[{"type":"union","types":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"},{"type":"literal","value":null}]},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"RequestPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"RequestPermissionMethod","package":"expo-modules-core"},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"GetPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"GetPermissionMethod","package":"expo-modules-core"}]}}]}},"defaultValue":"..."},{"name":"addListener","variant":"declaration","kind":64,"signatures":[{"name":"addListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Subscribes for updates in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"An ["},{"kind":"code","text":"`EventSubscription`"},{"kind":"text","text":"](#eventsubscription) object that you can call "},{"kind":"code","text":"`remove()`"},{"kind":"text","text":" on when\nyou would like to unsubscribe the listener."}]}]},"parameters":[{"name":"listener","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A callback that is fired when any assets have been inserted or deleted from the\nlibrary. On Android it's invoked with an empty object. On iOS it's invoked with\n["},{"kind":"code","text":"`MediaLibraryAssetsChangeEvent`"},{"kind":"text","text":"](#medialibraryassetschangeevent) object."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reference","name":"MediaLibraryAssetsChangeEvent","package":"expo-media-library"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"EventSubscription","package":"expo-modules-core"}}]},{"name":"getPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Checks user's permissions for accessing media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to check write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has\nan effect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPicker","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPicker","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows the user to update the assets that your app has access to.\nThe system modal is only displayed if the user originally allowed only "},{"kind":"code","text":"`limited`"},{"kind":"text","text":" access to their\nmedia library, otherwise this method is a no-op."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that either rejects if the method is unavailable, or resolves to "},{"kind":"code","text":"`void`"},{"kind":"text","text":".\n> __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\nThat information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using ["},{"kind":"code","text":"`addListener()`"},{"kind":"text","text":"](#medialibraryaddlistenerlistener).\nIf "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`false`"},{"kind":"text","text":", the user changed their permissions."}]},{"tag":"@platform","content":[{"kind":"text","text":"android 14+"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented."}]},"type":{"type":"array","elementType":{"type":"reference","name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"removeAllListeners","variant":"declaration","kind":64,"signatures":[{"name":"removeAllListeners","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes all listeners."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"requestPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"requestPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks the user to grant permissions for accessing media in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to request write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has an\neffect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions.\n\n> When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"Subscription","variant":"reference","kind":4194304}],"packageName":"expo-media-library"} \ No newline at end of file diff --git a/docs/public/static/data/unversioned/expo-media-library.json b/docs/public/static/data/unversioned/expo-media-library.json index 284a84f2a93d79..f83d5c343c0f4e 100644 --- a/docs/public/static/data/unversioned/expo-media-library.json +++ b/docs/public/static/data/unversioned/expo-media-library.json @@ -1 +1 @@ -{"schemaVersion":"2.0","name":"expo-media-library","variant":"project","kind":1,"children":[{"name":"AssetField","variant":"declaration","kind":8,"children":[{"name":"CREATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"creationTime"}},{"name":"DURATION","variant":"declaration","kind":16,"type":{"type":"literal","value":"duration"}},{"name":"HEIGHT","variant":"declaration","kind":16,"type":{"type":"literal","value":"height"}},{"name":"MEDIA_TYPE","variant":"declaration","kind":16,"type":{"type":"literal","value":"mediaType"}},{"name":"MODIFICATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"modificationTime"}},{"name":"WIDTH","variant":"declaration","kind":16,"type":{"type":"literal","value":"width"}}]},{"name":"MediaSubtype","variant":"declaration","kind":8,"comment":{"summary":[{"kind":"text","text":"Describes specific variations of asset media. Maps to ["},{"kind":"code","text":"`PHAssetMediaSubtype`"},{"kind":"text","text":"](https://developer.apple.com/documentation/photokit/phassetmediasubtype)."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"children":[{"name":"DEPTH_EFFECT","variant":"declaration","kind":16,"type":{"type":"literal","value":"depthEffect"}},{"name":"HDR","variant":"declaration","kind":16,"type":{"type":"literal","value":"hdr"}},{"name":"HIGH_FRAME_RATE","variant":"declaration","kind":16,"type":{"type":"literal","value":"highFrameRate"}},{"name":"LIVE_PHOTO","variant":"declaration","kind":16,"type":{"type":"literal","value":"livePhoto"}},{"name":"PANORAMA","variant":"declaration","kind":16,"type":{"type":"literal","value":"panorama"}},{"name":"SCREENSHOT","variant":"declaration","kind":16,"type":{"type":"literal","value":"screenshot"}},{"name":"SPATIAL_MEDIA","variant":"declaration","kind":16,"type":{"type":"literal","value":"spatialMedia"}},{"name":"STREAM","variant":"declaration","kind":16,"type":{"type":"literal","value":"stream"}},{"name":"TIME_LAPSE","variant":"declaration","kind":16,"type":{"type":"literal","value":"timelapse"}},{"name":"VIDEO_CINEMATIC","variant":"declaration","kind":16,"type":{"type":"literal","value":"videoCinematic"}}]},{"name":"MediaType","variant":"declaration","kind":8,"children":[{"name":"AUDIO","variant":"declaration","kind":16,"type":{"type":"literal","value":"audio"}},{"name":"IMAGE","variant":"declaration","kind":16,"type":{"type":"literal","value":"image"}},{"name":"UNKNOWN","variant":"declaration","kind":16,"type":{"type":"literal","value":"unknown"}},{"name":"VIDEO","variant":"declaration","kind":16,"type":{"type":"literal","value":"video"}}]},{"name":"PermissionStatus","variant":"declaration","kind":8,"children":[{"name":"DENIED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has denied the permission."}]},"type":{"type":"literal","value":"denied"}},{"name":"GRANTED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has granted the permission."}]},"type":{"type":"literal","value":"granted"}},{"name":"UNDETERMINED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User hasn't granted or denied the permission yet."}]},"type":{"type":"literal","value":"undetermined"}}]},{"name":"Album","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Album","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitialize an instance of an album with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unique identifier of the album."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Album","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Unique identifier of the album.\nCan be used to re-instantiate an [Album](#album) later."}]},"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.id"}},{"name":"add","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"add","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Adds one or more assets to the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been added."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///path/to/photo.png\");\nawait album.add(asset);\n```"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.add([asset1, asset2]);\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The [Asset](#asset) or list of [Asset](#asset) objects to add."}]},"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.add","package":"expo-media-library"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Permanently deletes the album from the device.\nOn Android, it deletes the album and all its assets.\nOn iOS, it deletes the album but keeps the assets in the main library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the deletion fails or the album could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"getAssets","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getAssets","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Retrieves all assets contained in the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of [Asset](#asset) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nconsole.log(assets.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAssets"}},{"name":"getTitle","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getTitle","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the display title (name) of the album.\nNote that album titles are not guaranteed to be unique."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the album’s title string."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst title = await album.getTitle();\nconsole.log(title); // \"Camera\"\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getTitle"}},{"name":"removeAssets","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"removeAssets","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Removes assets from the album without deleting them from the library.\nThis is supported only on iOS.\n\nOn Android, an asset can belong to only one album. To remove it from an album,\ndelete it or add it to another album."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been removed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nawait album.removeAssets(assets.slice(0, 2));\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of [Asset](#asset) objects to remove from the album."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.removeAssets"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new album with a given name and assets.\nOn Android, if assets are provided and "},{"kind":"code","text":"`moveAssets`"},{"kind":"text","text":" is true, the assets will be moved into the new album. If false or not supported, the assets will be copied."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created [Album](#album)."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nconsole.log(await album.getTitle()); // \"My Album\"\n```"}]}]},"parameters":[{"name":"name","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the new album."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"assetsRefs","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"List of [Asset](#asset) objects or file paths (file:///...) to include."}]},"type":{"type":"union","types":[{"type":"array","elementType":{"type":"intrinsic","name":"string"}},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}]}},{"name":"moveAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On Android, whether to move assets into the album. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple albums at once.\nOn Android, assets are always deleted along with the album regardless of "},{"kind":"code","text":"`deleteAssets`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the albums have been deleted."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nawait Album.delete([album]);\n```"}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of [Album](#album) instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}},{"name":"deleteAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On iOS, whether to delete the assets in the albums as well. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.delete"}},{"name":"get","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"get","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves an album by its title."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the [Album](#album) if found, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.get(\"Camera\");\nif (album) {\n console.log(await album.getTitle()); // \"Camera\"\n}\n```"}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The title of the album to retrieve."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.get"}},{"name":"getAll","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"getAll","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves all albums on the device."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of [Album](#album) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await Album.getAll();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Album.getAll"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Album"},"name":"Album","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Album"}]},{"name":"Asset","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Asset","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitialize an instance of an asset with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"For Android, it is a "},{"kind":"code","text":"`contentUri`"},{"kind":"text","text":" (content://media/external/images/media/12345) and for iOS, it is "},{"kind":"code","text":"`PHAsset`"},{"kind":"text","text":" localIdentifier URI."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Asset","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.constructor","package":"expo-media-library"}},{"name":"id","variant":"declaration","kind":1024,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"ID of the asset.\nCan be used to re-instantiate an [Asset](#asset) later.\nFor android it is a contentUri and PHAsset localIdentifier URI for iOS."}]},"type":{"type":"intrinsic","name":"string"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.id"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Deletes the asset from the device’s media store."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait asset.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}},{"name":"getAlbums","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getAlbums","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the albums containing this asset.\nOn Android, an asset is typically associated with a single album.\nOn iOS, an asset may belong to multiple albums."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of [Album](#album) objects."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await asset.getAlbums();\nconsole.log(albums.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getAlbums"}},{"name":"getCreationTime","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getCreationTime","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the creation time of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the UNIX timestamp in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getCreationTime","package":"expo-media-library"}},{"name":"getDuration","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getDuration","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the duration of the asset.\nApplies only to assets with media type [MediaType.audio](#mediatype) or [MediaType.video](#mediatype).\nFor other media types, it returns "},{"kind":"code","text":"`null`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the duration in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not applicable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getDuration","package":"expo-media-library"}},{"name":"getExif","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getExif","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the exif data of the [MediaType.image](#mediatype) asset.\nOn Android, this method requires the "},{"kind":"code","text":"`ACCESS_MEDIA_LOCATION`"},{"kind":"text","text":" permission to access location metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the exif data object or an empty object if the exif data is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getExif","package":"expo-media-library"}},{"name":"getFavorite","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getFavorite","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is marked as a favorite.\nOn iOS, this checks if the asset is part of the system \"Favorites\" smart album.\nOn Android, this reads the "},{"kind":"code","text":"`IS_FAVORITE`"},{"kind":"text","text":" column from MediaStore (requires Android 10+; always returns "},{"kind":"code","text":"`false`"},{"kind":"text","text":" on older versions)."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is a favorite, or "},{"kind":"code","text":"`false`"},{"kind":"text","text":" otherwise."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst isFavorite = await asset.getFavorite();\nconsole.log(isFavorite); // true or false\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFavorite"}},{"name":"getFilename","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getFilename","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the filename of the asset, including its extension."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the filename string."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getFilename"}},{"name":"getHeight","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getHeight","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the height of the asset in pixels.\nOnly applicable for image and video assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the height in pixels."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the filename cannot be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getHeight"}},{"name":"getInfo","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getInfo","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets detailed information about the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an [AssetInfo](#assetinfo)"}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found.\n\n> **Note:** On Android, the "},{"kind":"code","text":"`isFavorite`"},{"kind":"text","text":" field reflects the MediaStore "},{"kind":"code","text":"`IS_FAVORITE`"},{"kind":"text","text":" column, which some third-party gallery apps may not use for their own favorites."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getInfo"}},{"name":"getIsInCloud","variant":"declaration","kind":2048,"signatures":[{"name":"getIsInCloud","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is stored in iCloud and not available locally.\nThis does not trigger a download of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is stored in iCloud and not available locally."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getIsInCloud"}},{"name":"getLivePhotoVideoUri","variant":"declaration","kind":2048,"signatures":[{"name":"getLivePhotoVideoUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the URI of the paired video for a Live Photo asset.\nThe video is extracted to a temporary file."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a "},{"kind":"code","text":"`file://`"},{"kind":"text","text":" URI string, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the asset is not a Live Photo."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLivePhotoVideoUri","package":"expo-media-library"}},{"name":"getLocation","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getLocation","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the location of the asset.\nOn Android, this method requires the "},{"kind":"code","text":"`ACCESS_MEDIA_LOCATION`"},{"kind":"text","text":" permission to access location metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the [Location](#location) object or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the location data is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found, or if the permission is not granted on Android."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Location","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getLocation","package":"expo-media-library"}},{"name":"getMediaSubtypes","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaSubtypes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of [MediaSubtype](#mediasubtype) strings. Returns an empty array if no subtypes apply."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"MediaSubtype","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaSubtypes"}},{"name":"getMediaType","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getMediaType","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the media type of the asset (image, video, audio or unknown)."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a [MediaType](#mediatype) enum value."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"MediaType","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getMediaType"}},{"name":"getModificationTime","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getModificationTime","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the last modification time of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the UNIX timestamp in milliseconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getModificationTime","package":"expo-media-library"}},{"name":"getOrientation","variant":"declaration","kind":2048,"signatures":[{"name":"getOrientation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the EXIF display orientation of the asset.\nOnly applicable for assets with media type [MediaType.image](#mediatype)."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a value between 1 and 8 as defined by the [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html), or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getOrientation","package":"expo-media-library"}},{"name":"getShape","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getShape","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the shape (width and height) of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the [Shape](#shape) object, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if any dimension is unavailable."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Shape","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getShape","package":"expo-media-library"}},{"name":"getUri","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getUri","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the URI pointing to the asset’s location in the system.\nExample, for Android: "},{"kind":"code","text":"`file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the string URI."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getUri"}},{"name":"getWidth","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"getWidth","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Gets the width of the asset in pixels.\nOnly applicable for image and video assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the width in pixels."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be found."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.getWidth"}},{"name":"setFavorite","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"setFavorite","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Marks or unmarks the asset as a favorite.\nOn iOS, this adds or removes the asset from the system \"Favorites\" smart album.\nOn Android, this updates the "},{"kind":"code","text":"`IS_FAVORITE`"},{"kind":"text","text":" column in MediaStore (requires Android 10+; no-op on older versions)."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the operation has completed.\n\n> **Note:** On Android, some third-party gallery apps maintain their own favorites list and may not reflect changes made through this method."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait asset.setFavorite(true);\n```"}]}]},"parameters":[{"name":"isFavorite","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the asset should be marked as favorite."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.setFavorite"}},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new asset from a given file path.\nOptionally associates the asset with an album. On Android, if not specified, the asset will be placed in the default \"Pictures\" directory."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created [Asset](#asset)."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the asset could not be created, for example, if the file does not exist or permission is denied."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg\");\nconsole.log(await asset.getFilename()); // \"IMG_20230915_123456.jpg\"\n```"}]}]},"parameters":[{"name":"filePath","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Local filesystem path (for example, "},{"kind":"code","text":"`file:///...`"},{"kind":"text","text":") of the file to import."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional [Album](#album) instance to place the asset in."}]},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.create"}},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true,"isInherited":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple assets from the device's media store."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of [Asset](#asset) instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Asset.delete"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Asset"},"name":"Asset","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Asset"}]},{"name":"Query","variant":"declaration","kind":128,"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Query","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Initializes a new, empty query."}]},"type":{"type":"reference","name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}},{"name":"album","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"album","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets to only those contained in the specified album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The album to filter assets by."}]},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Album.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}},{"name":"eq","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"eq","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should equal. Each field has a specific unique type."}]},"type":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}},{"name":"exe","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"exe","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Executes the query and retrieves the matching assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves to an array of [Asset](#asset) objects that match the query criteria."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await new Query()\n .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n .lte(AssetField.HEIGHT, 1080)\n .orderBy(AssetField.CREATION_TIME)\n .limit(20)\n .exe();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Asset.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}},{"name":"gt","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"gt","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}},{"name":"gte","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"gte","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than or equal to the given value."}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}},{"name":"limit","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"limit","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Limits the number of results returned by the query."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The maximum number of results to return."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}},{"name":"lt","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"lt","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}},{"name":"lte","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"lte","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}},{"name":"offset","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"offset","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Skips the specified number of results."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"offset","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The number of results to skip."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}},{"name":"orderBy","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"orderBy","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Orders the results by the specified sort descriptor or asset field."}]},"parameters":[{"name":"sortDescriptors","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default."}]},"type":{"type":"union","types":[{"type":"reference","name":"AssetField","package":"expo-media-library"},{"type":"reference","name":"SortDescriptor","package":"expo-media-library"}]}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}},{"name":"within","variant":"declaration","kind":2048,"flags":{"isInherited":true},"signatures":[{"name":"within","variant":"signature","kind":4096,"flags":{"isInherited":true},"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field's value is in the given array of values."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an [AssetField](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of values that the field should match. Each field has a specific unique type."}]},"type":{"type":"array","elementType":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}}],"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/types/Query.ts","qualifiedName":"Query"},"name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/ExpoMediaLibraryNext.ts","qualifiedName":"ExpoMediaLibraryNextModule.Query"},"name":"Query","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Query"}]},{"name":"EventSubscription","variant":"declaration","kind":256,"comment":{"summary":[{"kind":"text","text":"A subscription object that allows to conveniently remove an event listener from the emitter."}]},"children":[{"name":"remove","variant":"declaration","kind":2048,"signatures":[{"name":"remove","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes an event listener for which the subscription has been created.\nAfter calling this function, the listener will no longer receive any events from the emitter."}]},"type":{"type":"intrinsic","name":"void"}}]}]},{"name":"AssetFieldValueMap","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"AssetInfo","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"filename","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"id","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"isFavorite","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"uri","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"GranularPermission","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"audio"},{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"Location","variant":"declaration","kind":2097152,"children":[{"name":"latitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"longitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"MediaLibraryAssetsChangeEvent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An event emitted when assets in the media library change."}]},"children":[{"name":"deletedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been deleted from the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"hasIncrementalChanges","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Whether the media library's changes can be described as incremental changes.\n"},{"kind":"code","text":"`true`"},{"kind":"text","text":" indicates the changes are described by the "},{"kind":"code","text":"`insertedAssets`"},{"kind":"text","text":", "},{"kind":"code","text":"`deletedAssets`"},{"kind":"text","text":" and\n"},{"kind":"code","text":"`updatedAssets`"},{"kind":"text","text":" values. "},{"kind":"code","text":"`false`"},{"kind":"text","text":" indicates that the scope of changes is too large and you\nshould perform a full assets reload.\nOn Android this is always "},{"kind":"code","text":"`false`"},{"kind":"text","text":" because the platform does not provide incremental change details."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"insertedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been inserted to the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"updatedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been updated.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}}]},{"name":"MediaTypeFilter","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"PermissionHookOptions","variant":"declaration","kind":2097152,"typeParameters":[{"name":"Options","variant":"typeParam","kind":131072,"type":{"type":"intrinsic","name":"object"}}],"type":{"type":"intersection","types":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"PermissionHookBehavior"},"name":"PermissionHookBehavior","package":"expo-modules-core"},{"type":"reference","name":"Options","package":"expo-modules-core","refersToTypeParameter":true}]}},{"name":"PermissionResponse","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An object obtained by permissions get and request functions."}]},"children":[{"name":"canAskAgain","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Indicates if user can be asked again for specific permission.\nIf not, one should be directed to the Settings app\nin order to enable/disable the permission."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"expires","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines time when the permission expires."}]},"type":{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsInterface.ts","qualifiedName":"PermissionExpiration"},"name":"PermissionExpiration","package":"expo-modules-core"}},{"name":"granted","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"A convenience boolean that indicates if the permission is granted."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"status","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines the status of the permission."}]},"type":{"type":"reference","name":"PermissionStatus","package":"expo-modules-core"}}]},{"name":"Shape","variant":"declaration","kind":2097152,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"SortDescriptor","variant":"declaration","kind":2097152,"children":[{"name":"ascending","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"key","variant":"declaration","kind":1024,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}]},{"name":"usePermissions","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Check or request permissions to access the media library.\nThis uses both "},{"kind":"code","text":"`requestPermissionsAsync`"},{"kind":"text","text":" and "},{"kind":"code","text":"`getPermissionsAsync`"},{"kind":"text","text":" to interact with the permissions."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n writeOnly: true,\n granularPermissions: ['photo'],\n});\n```"}]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"granularPermissions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}},{"name":"writeOnly","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}],"name":"PermissionHookOptions","package":"expo-modules-core"}}],"type":{"type":"tuple","elements":[{"type":"union","types":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"},{"type":"literal","value":null}]},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"RequestPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"RequestPermissionMethod","package":"expo-modules-core"},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"GetPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"GetPermissionMethod","package":"expo-modules-core"}]}}]}},"defaultValue":"..."},{"name":"addAssetsToAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"addAssetsToAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.add()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}},{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}},{"name":"copy","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"addListener","variant":"declaration","kind":64,"signatures":[{"name":"addListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Subscribes for updates in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"An ["},{"kind":"code","text":"`EventSubscription`"},{"kind":"text","text":"](#eventsubscription) object that you can call "},{"kind":"code","text":"`remove()`"},{"kind":"text","text":" on when\nyou would like to unsubscribe the listener."}]}]},"parameters":[{"name":"listener","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A callback that is fired when any assets have been inserted or deleted from the\nlibrary. On Android it's invoked with an empty object. On iOS it's invoked with\n["},{"kind":"code","text":"`MediaLibraryAssetsChangeEvent`"},{"kind":"text","text":"](#medialibraryassetschangeevent) object."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reference","name":"MediaLibraryAssetsChangeEvent","package":"expo-media-library"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"EventSubscription","package":"expo-modules-core"}}]},{"name":"albumNeedsMigrationAsync","variant":"declaration","kind":64,"signatures":[{"name":"albumNeedsMigrationAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"createAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"createAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"albumName","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"asset","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"copyAsset","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"initialAssetLocalUri","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"createAssetAsync","variant":"declaration","kind":64,"signatures":[{"name":"createAssetAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Asset.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"localUri","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"deleteAlbumsAsync","variant":"declaration","kind":64,"signatures":[{"name":"deleteAlbumsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.delete()`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Album.delete()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}]}},{"name":"assetRemove","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"deleteAssetsAsync","variant":"declaration","kind":64,"signatures":[{"name":"deleteAssetsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.delete()`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Asset.delete()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"getAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.get(title)`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getAlbumsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAlbumsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.getAll()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumsOptions"},"name":"AlbumsOptions","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getAssetInfoAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAssetInfoAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.getInfo()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"asset","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"MediaLibraryAssetInfoQueryOptions"},"name":"MediaLibraryAssetInfoQueryOptions","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetInfo"},"name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getAssetsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAssetsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use the "},{"kind":"code","text":"`Query`"},{"kind":"text","text":" class or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assetsOptions","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetsOptions"},"name":"AssetsOptions","package":"expo-media-library"},"defaultValue":"{}"}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"PagedInfo"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"PagedInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getMomentsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getMomentsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Checks user's permissions for accessing media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to check write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has\nan effect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"isAvailableAsync","variant":"declaration","kind":64,"signatures":[{"name":"isAvailableAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"migrateAlbumIfNeededAsync","variant":"declaration","kind":64,"signatures":[{"name":"migrateAlbumIfNeededAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPicker","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPicker","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows the user to update the assets that your app has access to.\nThe system modal is only displayed if the user originally allowed only "},{"kind":"code","text":"`limited`"},{"kind":"text","text":" access to their\nmedia library, otherwise this method is a no-op."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that either rejects if the method is unavailable, or resolves to "},{"kind":"code","text":"`void`"},{"kind":"text","text":".\n> __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\nThat information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using ["},{"kind":"code","text":"`addListener()`"},{"kind":"text","text":"](#medialibraryaddlistenerlistener).\nIf "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`false`"},{"kind":"text","text":", the user changed their permissions."}]},{"tag":"@platform","content":[{"kind":"text","text":"android 14+"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented."}]},"type":{"type":"array","elementType":{"type":"reference","name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPickerAsync","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPickerAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`presentPermissionsPicker()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"MediaTypeFilter"},"name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"removeAllListeners","variant":"declaration","kind":64,"signatures":[{"name":"removeAllListeners","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes all listeners."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"removeAssetsFromAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"removeAssetsFromAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.removeAssets()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}},{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"removeSubscription","variant":"declaration","kind":64,"signatures":[{"name":"removeSubscription","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`subscription.remove()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"subscription","variant":"param","kind":32768,"type":{"type":"reference","name":"EventSubscription","package":"expo-modules-core"}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"requestPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"requestPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks the user to grant permissions for accessing media in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to request write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has an\neffect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions.\n\n> When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"saveToLibraryAsync","variant":"declaration","kind":64,"signatures":[{"name":"saveToLibraryAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Asset.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"localUri","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"setAssetFavoriteAsync","variant":"declaration","kind":64,"signatures":[{"name":"setAssetFavoriteAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.setFavorite()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"asset","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"isFavorite","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]}],"packageName":"expo-media-library"} \ No newline at end of file +{"schemaVersion":"2.0","name":"expo-media-library","variant":"project","kind":1,"children":[{"name":"AssetField","variant":"declaration","kind":8,"children":[{"name":"CREATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"creationTime"}},{"name":"DURATION","variant":"declaration","kind":16,"type":{"type":"literal","value":"duration"}},{"name":"HEIGHT","variant":"declaration","kind":16,"type":{"type":"literal","value":"height"}},{"name":"IS_FAVORITE","variant":"declaration","kind":16,"type":{"type":"literal","value":"isFavorite"}},{"name":"MEDIA_TYPE","variant":"declaration","kind":16,"type":{"type":"literal","value":"mediaType"}},{"name":"MODIFICATION_TIME","variant":"declaration","kind":16,"type":{"type":"literal","value":"modificationTime"}},{"name":"WIDTH","variant":"declaration","kind":16,"type":{"type":"literal","value":"width"}}]},{"name":"MediaSubtype","variant":"declaration","kind":8,"comment":{"summary":[{"kind":"text","text":"Describes specific variations of asset media. Maps to ["},{"kind":"code","text":"`PHAssetMediaSubtype`"},{"kind":"text","text":"](https://developer.apple.com/documentation/photokit/phassetmediasubtype)."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"children":[{"name":"DEPTH_EFFECT","variant":"declaration","kind":16,"type":{"type":"literal","value":"depthEffect"}},{"name":"HDR","variant":"declaration","kind":16,"type":{"type":"literal","value":"hdr"}},{"name":"HIGH_FRAME_RATE","variant":"declaration","kind":16,"type":{"type":"literal","value":"highFrameRate"}},{"name":"LIVE_PHOTO","variant":"declaration","kind":16,"type":{"type":"literal","value":"livePhoto"}},{"name":"PANORAMA","variant":"declaration","kind":16,"type":{"type":"literal","value":"panorama"}},{"name":"SCREENSHOT","variant":"declaration","kind":16,"type":{"type":"literal","value":"screenshot"}},{"name":"SPATIAL_MEDIA","variant":"declaration","kind":16,"type":{"type":"literal","value":"spatialMedia"}},{"name":"STREAM","variant":"declaration","kind":16,"type":{"type":"literal","value":"stream"}},{"name":"TIME_LAPSE","variant":"declaration","kind":16,"type":{"type":"literal","value":"timelapse"}},{"name":"VIDEO_CINEMATIC","variant":"declaration","kind":16,"type":{"type":"literal","value":"videoCinematic"}}]},{"name":"MediaType","variant":"declaration","kind":8,"children":[{"name":"AUDIO","variant":"declaration","kind":16,"type":{"type":"literal","value":"audio"}},{"name":"IMAGE","variant":"declaration","kind":16,"type":{"type":"literal","value":"image"}},{"name":"UNKNOWN","variant":"declaration","kind":16,"type":{"type":"literal","value":"unknown"}},{"name":"VIDEO","variant":"declaration","kind":16,"type":{"type":"literal","value":"video"}}]},{"name":"PermissionStatus","variant":"declaration","kind":8,"children":[{"name":"DENIED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has denied the permission."}]},"type":{"type":"literal","value":"denied"}},{"name":"GRANTED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User has granted the permission."}]},"type":{"type":"literal","value":"granted"}},{"name":"UNDETERMINED","variant":"declaration","kind":16,"comment":{"summary":[{"kind":"text","text":"User hasn't granted or denied the permission yet."}]},"type":{"type":"literal","value":"undetermined"}}]},{"name":"Album","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a media album (collection of assets) on the device.\n\nAn ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) groups together media assets (images, videos, or audio files).\nTo create a new album, use "},{"kind":"code","text":"`Album.create()`"},{"kind":"text","text":".\nTo fetch an existing album, use "},{"kind":"code","text":"`Album.get()`"},{"kind":"text","text":"."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Album","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitializes an instance of an album with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The unique identifier of the album."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Album","package":"expo-media-library"}}]},{"name":"id","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Unique identifier of the album.\nCan be used to re-instantiate an ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) later."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"add","variant":"declaration","kind":2048,"signatures":[{"name":"add","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Adds one or more assets to the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been added."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst asset = await Asset.create(\"file:///path/to/photo.png\");\nawait album.add(asset);\n```"}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.add([asset1, asset2]);\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) or list of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects to add."}]},"type":{"type":"union","types":[{"type":"reference","name":"Asset","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"delete","variant":"declaration","kind":2048,"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Permanently deletes the album from the device.\nOn Android, it deletes the album and all its assets.\nOn iOS, it deletes the album but keeps the assets in the main library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the deletion has completed."}]},{"tag":"@throws","content":[{"kind":"text","text":"An exception if the deletion fails or the album could not be found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nawait album.delete();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"getAssets","variant":"declaration","kind":2048,"signatures":[{"name":"getAssets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Retrieves all assets contained in the album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nconsole.log(assets.length);\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getTitle","variant":"declaration","kind":2048,"signatures":[{"name":"getTitle","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the display title (name) of the album.\nNote that album titles are not guaranteed to be unique."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the album's title string."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst title = await album.getTitle();\nconsole.log(title); // \"Camera\"\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"}}]},{"name":"removeAssets","variant":"declaration","kind":2048,"signatures":[{"name":"removeAssets","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes assets from the album without deleting them from the library.\nThis is supported only on iOS.\n\nOn Android, an asset can belong to only one album. To remove it from an album,\ndelete it or add it to another album."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]},{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the assets have been removed."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await album.getAssets();\nawait album.removeAssets(assets.slice(0, 2));\n```"}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects to remove from the album."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Creates a new album with a given name and assets.\nOn Android, if assets are provided and "},{"kind":"code","text":"`moveAssets`"},{"kind":"text","text":" is true, the assets will be moved into the new album. If false or not supported, the assets will be copied."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album)."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nconsole.log(await album.getTitle()); // \"My Album\"\n```"}]}]},"parameters":[{"name":"name","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Name of the new album."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"assetsRefs","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"List of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects or file paths (file:///...) to include."}]},"type":{"type":"union","types":[{"type":"array","elementType":{"type":"intrinsic","name":"string"}},{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}]}},{"name":"moveAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On Android, whether to move assets into the album. Defaults to "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Deletes multiple albums at once.\nOn Android, assets are always deleted along with the album regardless of "},{"kind":"code","text":"`deleteAssets`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the albums have been deleted."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.create(\"My Album\", [asset]);\nawait Album.delete([album]);\n```"}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) instances to delete."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}},{"name":"deleteAssets","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"On iOS, whether to delete the assets in the albums as well. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"get","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"get","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves an album by its title."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) if found, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if not found."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst album = await Album.get(\"Camera\");\nif (album) {\n console.log(await album.getTitle()); // \"Camera\"\n}\n```"}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The title of the album to retrieve."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Album","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getAll","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"getAll","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"A static function. Retrieves all albums on the device."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) objects."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst albums = await Album.getAll();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Album"},"name":"Album","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Album"}]},{"name":"Asset","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a media asset in the device media library."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Asset","variant":"signature","kind":16384,"comment":{"summary":[{"kind":"text","text":"Reinitializes an instance of an asset with a given ID."}]},"parameters":[{"name":"id","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The asset identifier. On Android, this is a "},{"kind":"code","text":"`content://`"},{"kind":"text","text":" URI. On iOS, this is a "},{"kind":"code","text":"`PHAsset`"},{"kind":"text","text":" local identifier URI."}]},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","name":"Asset","package":"expo-media-library"}}]},{"name":"id","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Asset identifier.\nCan be used to re-instantiate an ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) later. Hello world"}]},"type":{"type":"intrinsic","name":"string"}},{"name":"delete","variant":"declaration","kind":2048,"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Deletes the asset from the media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving once the deletion has completed."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"getAlbums","variant":"declaration","kind":2048,"signatures":[{"name":"getAlbums","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets albums that contain the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`Album`"},{"kind":"text","text":"](#album) objects."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getCreationTime","variant":"declaration","kind":2048,"signatures":[{"name":"getCreationTime","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset creation time."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a timestamp in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getDuration","variant":"declaration","kind":2048,"signatures":[{"name":"getDuration","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset duration."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the duration in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getExif","variant":"declaration","kind":2048,"signatures":[{"name":"getExif","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset EXIF metadata."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a map of EXIF tags."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"indexSignatures":[{"name":"__index","variant":"signature","kind":8192,"parameters":[{"name":"key","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"intrinsic","name":"any"}}]}}],"name":"Promise","package":"typescript"}}]},{"name":"getFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"getFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is marked as a favorite.\nOn iOS, this checks if the asset is part of the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is marked as favorite, otherwise "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"getFilename","variant":"declaration","kind":2048,"signatures":[{"name":"getFilename","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset filename."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset filename."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"}}]},{"name":"getHeight","variant":"declaration","kind":2048,"signatures":[{"name":"getHeight","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset height."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset height in pixels."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"}}]},{"name":"getInfo","variant":"declaration","kind":2048,"signatures":[{"name":"getInfo","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets complete information about the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an ["},{"kind":"code","text":"`AssetInfo`"},{"kind":"text","text":"](#assetinfo) object."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getIsInCloud","variant":"declaration","kind":2048,"signatures":[{"name":"getIsInCloud","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets whether the asset is stored in iCloud and not available locally.\nThis does not trigger a download of the asset."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to "},{"kind":"code","text":"`true`"},{"kind":"text","text":" if the asset is stored in iCloud and unavailable locally, otherwise "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"getLivePhotoVideoUri","variant":"declaration","kind":2048,"signatures":[{"name":"getLivePhotoVideoUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the URI of the paired video for a Live Photo asset.\nThe video is extracted to a temporary file."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the paired video URI, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" if the asset is not a Live Photo or no paired video is available."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"string"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getLocation","variant":"declaration","kind":2048,"signatures":[{"name":"getLocation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset location."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset location, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when location is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Location","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getMediaSubtypes","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaSubtypes","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to an array of ["},{"kind":"code","text":"`MediaSubtype`"},{"kind":"text","text":"](#mediasubtype) values."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"MediaSubtype","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getMediaType","variant":"declaration","kind":2048,"signatures":[{"name":"getMediaType","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset media type."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset media type."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"MediaType","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getModificationTime","variant":"declaration","kind":2048,"signatures":[{"name":"getModificationTime","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset modification time."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to a timestamp in seconds, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getOrientation","variant":"declaration","kind":2048,"signatures":[{"name":"getOrientation","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the EXIF display orientation of the asset.\nOnly applicable for assets with media type "},{"kind":"code","text":"`MediaType.IMAGE`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the EXIF orientation value, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when unavailable."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getShape","variant":"declaration","kind":2048,"signatures":[{"name":"getShape","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset dimensions."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset shape, or "},{"kind":"code","text":"`null`"},{"kind":"text","text":" when the value is unavailable."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"union","types":[{"type":"reference","name":"Shape","package":"expo-media-library"},{"type":"literal","value":null}]}],"name":"Promise","package":"typescript"}}]},{"name":"getUri","variant":"declaration","kind":2048,"signatures":[{"name":"getUri","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset URI."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset URI."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"string"}],"name":"Promise","package":"typescript"}}]},{"name":"getWidth","variant":"declaration","kind":2048,"signatures":[{"name":"getWidth","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Gets the asset width."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the asset width in pixels."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"number"}],"name":"Promise","package":"typescript"}}]},{"name":"setFavorite","variant":"declaration","kind":2048,"signatures":[{"name":"setFavorite","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Marks or unmarks the asset as a favorite. On iOS, this adds or removes the asset from the system \"Favorites\" smart album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves once the favorite state has been updated."}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"isFavorite","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether the asset should be marked as favorite."}]},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"create","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"create","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Creates an asset from a local file path."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving to the created ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset)."}]}]},"parameters":[{"name":"filePath","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Local file URI of the asset to create."}]},"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Optional album to add the created asset to."}]},"type":{"type":"reference","name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"delete","variant":"declaration","kind":2048,"flags":{"isStatic":true},"signatures":[{"name":"delete","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Deletes multiple assets from the media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise resolving once deletion has completed."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Assets to delete."}]},"type":{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Asset"},"name":"Asset","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Asset"}]},{"name":"Query","variant":"declaration","kind":128,"comment":{"summary":[{"kind":"text","text":"Represents a query to fetch data from the media library.\n\nA "},{"kind":"code","text":"`query`"},{"kind":"text","text":" implements a builder pattern, allowing you to chain multiple filtering and sorting methods\nto construct complex queries."}]},"children":[{"name":"constructor","variant":"declaration","kind":512,"signatures":[{"name":"Query","variant":"signature","kind":16384,"type":{"type":"reference","name":"Query","package":"expo-media-library"},"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}}],"inheritedFrom":{"type":"reference","name":"ExpoMediaLibraryNext.Query.constructor","package":"expo-media-library"}},{"name":"album","variant":"declaration","kind":2048,"signatures":[{"name":"album","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets to only those contained in the specified album."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The album to filter assets by."}]},"type":{"type":"reference","name":"Album","package":"expo-media-library"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.album"}},{"name":"eq","variant":"declaration","kind":2048,"signatures":[{"name":"eq","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should equal. Each field has a specific unique type."}]},"type":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.eq","package":"expo-media-library"}},{"name":"exe","variant":"declaration","kind":2048,"signatures":[{"name":"exe","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes the query and retrieves the matching assets."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves to an array of ["},{"kind":"code","text":"`Asset`"},{"kind":"text","text":"](#asset) objects that match the query criteria."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await new Query()\n .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n .lte(AssetField.HEIGHT, 1080)\n .orderBy(AssetField.CREATION_TIME)\n .limit(20)\n .exe();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","name":"Asset","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exe"}},{"name":"exeForMetadata","variant":"declaration","kind":2048,"signatures":[{"name":"exeForMetadata","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Executes the query and retrieves lightweight metadata for the matching assets.\n\nReturns fields that can be read cheaply from the media store, without resolving file paths or\ndecoding files."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that resolves to an array of ["},{"kind":"code","text":"`AssetMetadata`"},{"kind":"text","text":"](#assetmetadata) objects that match the query criteria."}]},{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst assets = await new Query()\n .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n .lte(AssetField.HEIGHT, 1080)\n .orderBy(AssetField.CREATION_TIME)\n .limit(20)\n .exeForMetadata();\n```"}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/types/Asset.types.ts","qualifiedName":"AssetMetadata"},"name":"AssetMetadata","package":"expo-media-library"}}],"name":"Promise","package":"typescript"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exeForMetadata"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.exeForMetadata"}},{"name":"gt","variant":"declaration","kind":2048,"signatures":[{"name":"gt","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gt"}},{"name":"gte","variant":"declaration","kind":2048,"signatures":[{"name":"gte","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is greater than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be greater than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.gte"}},{"name":"limit","variant":"declaration","kind":2048,"signatures":[{"name":"limit","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Limits the number of results returned by the query."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"limit","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The maximum number of results to return."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.limit"}},{"name":"lt","variant":"declaration","kind":2048,"signatures":[{"name":"lt","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lt"}},{"name":"lte","variant":"declaration","kind":2048,"signatures":[{"name":"lte","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field is less than or equal to the given value."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The value that the field should be less than or equal to."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.lte"}},{"name":"offset","variant":"declaration","kind":2048,"signatures":[{"name":"offset","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Skips the specified number of results."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"offset","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"The number of results to skip."}]},"type":{"type":"intrinsic","name":"number"}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.offset"}},{"name":"orderBy","variant":"declaration","kind":2048,"signatures":[{"name":"orderBy","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Orders the results by the specified sort descriptor or asset field."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"parameters":[{"name":"sortDescriptors","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default."}]},"type":{"type":"union","types":[{"type":"reference","name":"AssetField","package":"expo-media-library"},{"type":"reference","name":"SortDescriptor","package":"expo-media-library"}]}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.orderBy","package":"expo-media-library"}},{"name":"within","variant":"declaration","kind":2048,"signatures":[{"name":"within","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Filters assets where the specified field's value is in the given array of values."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"The updated query object for chaining."}]}]},"typeParameters":[{"name":"T","variant":"typeParam","kind":131072,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}],"parameters":[{"name":"field","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"an ["},{"kind":"code","text":"`AssetField`"},{"kind":"text","text":"](#assetfield) to filter by."}]},"type":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true}},{"name":"value","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"An array of values that the field should match. Each field has a specific unique type."}]},"type":{"type":"array","elementType":{"type":"indexedAccess","indexType":{"type":"reference","name":"T","package":"expo-media-library","refersToTypeParameter":true},"objectType":{"type":"reference","name":"AssetFieldValueMap","package":"expo-media-library"}}}}],"type":{"type":"reference","name":"Query","package":"expo-media-library"},"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"overwrites":{"type":"reference","name":"ExpoMediaLibraryNext.Query.within","package":"expo-media-library"}}],"extendedTypes":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/next/native/index.ts","qualifiedName":"ExpoMediaLibraryNextModule.Query"},"name":"Query","package":"expo-media-library","qualifiedName":"ExpoMediaLibraryNextModule.Query"}]},{"name":"EventSubscription","variant":"declaration","kind":256,"comment":{"summary":[{"kind":"text","text":"A subscription object that allows to conveniently remove an event listener from the emitter."}]},"children":[{"name":"remove","variant":"declaration","kind":2048,"signatures":[{"name":"remove","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes an event listener for which the subscription has been created.\nAfter calling this function, the listener will no longer receive any events from the emitter."}]},"type":{"type":"intrinsic","name":"void"}}]}]},{"name":"AssetFieldValueMap","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"isFavorite","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"boolean"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"AssetInfo","variant":"declaration","kind":2097152,"children":[{"name":"creationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"duration","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"filename","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"id","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"isFavorite","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"mediaType","variant":"declaration","kind":1024,"type":{"type":"reference","name":"MediaType","package":"expo-media-library"}},{"name":"modificationTime","variant":"declaration","kind":1024,"type":{"type":"union","types":[{"type":"intrinsic","name":"number"},{"type":"literal","value":null}]}},{"name":"uri","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"string"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"GranularPermission","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"audio"},{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"Location","variant":"declaration","kind":2097152,"children":[{"name":"latitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"longitude","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"MediaLibraryAssetsChangeEvent","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An event emitted when assets in the media library change."}]},"children":[{"name":"deletedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been deleted from the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"hasIncrementalChanges","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Whether the media library's changes can be described as incremental changes.\n"},{"kind":"code","text":"`true`"},{"kind":"text","text":" indicates the changes are described by the "},{"kind":"code","text":"`insertedAssets`"},{"kind":"text","text":", "},{"kind":"code","text":"`deletedAssets`"},{"kind":"text","text":" and\n"},{"kind":"code","text":"`updatedAssets`"},{"kind":"text","text":" values. "},{"kind":"code","text":"`false`"},{"kind":"text","text":" indicates that the scope of changes is too large and you\nshould perform a full assets reload.\nOn Android this is always "},{"kind":"code","text":"`false`"},{"kind":"text","text":" because the platform does not provide incremental change details."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"insertedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been inserted to the library.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}},{"name":"updatedAssets","variant":"declaration","kind":1024,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Array of asset IDs ("},{"kind":"code","text":"`ph://`"},{"kind":"text","text":" URIs) that have been updated.\nOnly populated when "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`true`"},{"kind":"text","text":"."}],"blockTags":[{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"type":{"type":"array","elementType":{"type":"intrinsic","name":"string"}}}]},{"name":"MediaTypeFilter","variant":"declaration","kind":2097152,"type":{"type":"union","types":[{"type":"literal","value":"photo"},{"type":"literal","value":"video"}]}},{"name":"PermissionExpiration","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"Permission expiration time. Currently, all permissions are granted permanently."}]},"type":{"type":"union","types":[{"type":"literal","value":"never"},{"type":"intrinsic","name":"number"}]}},{"name":"PermissionHookOptions","variant":"declaration","kind":2097152,"typeParameters":[{"name":"Options","variant":"typeParam","kind":131072,"type":{"type":"intrinsic","name":"object"}}],"type":{"type":"intersection","types":[{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"PermissionHookBehavior"},"name":"PermissionHookBehavior","package":"expo-modules-core"},{"type":"reference","name":"Options","package":"expo-modules-core","refersToTypeParameter":true}]}},{"name":"PermissionResponse","variant":"declaration","kind":2097152,"comment":{"summary":[{"kind":"text","text":"An object obtained by permissions get and request functions."}]},"children":[{"name":"canAskAgain","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Indicates if user can be asked again for specific permission.\nIf not, one should be directed to the Settings app\nin order to enable/disable the permission."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"expires","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines time when the permission expires."}]},"type":{"type":"reference","name":"PermissionExpiration","package":"expo-modules-core"}},{"name":"granted","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"A convenience boolean that indicates if the permission is granted."}]},"type":{"type":"intrinsic","name":"boolean"}},{"name":"status","variant":"declaration","kind":1024,"comment":{"summary":[{"kind":"text","text":"Determines the status of the permission."}]},"type":{"type":"reference","name":"PermissionStatus","package":"expo-modules-core"}}]},{"name":"Shape","variant":"declaration","kind":2097152,"children":[{"name":"height","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}},{"name":"width","variant":"declaration","kind":1024,"type":{"type":"intrinsic","name":"number"}}]},{"name":"SortDescriptor","variant":"declaration","kind":2097152,"children":[{"name":"ascending","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"key","variant":"declaration","kind":1024,"type":{"type":"reference","name":"AssetField","package":"expo-media-library"}}]},{"name":"usePermissions","variant":"declaration","kind":32,"flags":{"isConst":true},"comment":{"summary":[{"kind":"text","text":"Check or request permissions to access the media library.\nThis uses both "},{"kind":"code","text":"`requestPermissionsAsync`"},{"kind":"text","text":" and "},{"kind":"code","text":"`getPermissionsAsync`"},{"kind":"text","text":" to interact with the permissions."}],"blockTags":[{"tag":"@example","content":[{"kind":"code","text":"```ts\nconst [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n writeOnly: true,\n granularPermissions: ['photo'],\n});\n```"}]}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","typeArguments":[{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"children":[{"name":"granularPermissions","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}},{"name":"writeOnly","variant":"declaration","kind":1024,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}]}}],"name":"PermissionHookOptions","package":"expo-modules-core"}}],"type":{"type":"tuple","elements":[{"type":"union","types":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"},{"type":"literal","value":null}]},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"RequestPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"RequestPermissionMethod","package":"expo-modules-core"},{"type":"reference","target":{"packageName":"expo-modules-core","packagePath":"src/PermissionsHook.ts","qualifiedName":"GetPermissionMethod"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"GetPermissionMethod","package":"expo-modules-core"}]}}]}},"defaultValue":"..."},{"name":"addAssetsToAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"addAssetsToAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.add()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}},{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}},{"name":"copy","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"addListener","variant":"declaration","kind":64,"signatures":[{"name":"addListener","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Subscribes for updates in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"An ["},{"kind":"code","text":"`EventSubscription`"},{"kind":"text","text":"](#eventsubscription) object that you can call "},{"kind":"code","text":"`remove()`"},{"kind":"text","text":" on when\nyou would like to unsubscribe the listener."}]}]},"parameters":[{"name":"listener","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"A callback that is fired when any assets have been inserted or deleted from the\nlibrary. On Android it's invoked with an empty object. On iOS it's invoked with\n["},{"kind":"code","text":"`MediaLibraryAssetsChangeEvent`"},{"kind":"text","text":"](#medialibraryassetschangeevent) object."}]},"type":{"type":"reflection","declaration":{"name":"__type","variant":"declaration","kind":65536,"signatures":[{"name":"__type","variant":"signature","kind":4096,"parameters":[{"name":"event","variant":"param","kind":32768,"type":{"type":"reference","name":"MediaLibraryAssetsChangeEvent","package":"expo-media-library"}}],"type":{"type":"intrinsic","name":"void"}}]}}}],"type":{"type":"reference","name":"EventSubscription","package":"expo-modules-core"}}]},{"name":"albumNeedsMigrationAsync","variant":"declaration","kind":64,"signatures":[{"name":"albumNeedsMigrationAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"createAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"createAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"albumName","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"asset","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"copyAsset","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}},{"name":"initialAssetLocalUri","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"createAssetAsync","variant":"declaration","kind":64,"signatures":[{"name":"createAssetAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Asset.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"localUri","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}},{"name":"album","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"deleteAlbumsAsync","variant":"declaration","kind":64,"signatures":[{"name":"deleteAlbumsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.delete()`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Album.delete()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"albums","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}]}},{"name":"assetRemove","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"deleteAssetsAsync","variant":"declaration","kind":64,"signatures":[{"name":"deleteAssetsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.delete()`"},{"kind":"text","text":" or "},{"kind":"code","text":"`Asset.delete()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"getAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.get(title)`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"title","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getAlbumsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAlbumsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Album.getAll()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumsOptions"},"name":"AlbumsOptions","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getAssetInfoAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAssetInfoAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.getInfo()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"asset","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"options","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"MediaLibraryAssetInfoQueryOptions"},"name":"MediaLibraryAssetInfoQueryOptions","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetInfo"},"name":"AssetInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getAssetsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getAssetsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use the "},{"kind":"code","text":"`Query`"},{"kind":"text","text":" class or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assetsOptions","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetsOptions"},"name":"AssetsOptions","package":"expo-media-library"},"defaultValue":"{}"}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"PagedInfo"},"typeArguments":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Asset"},"name":"Asset","package":"expo-media-library"}],"name":"PagedInfo","package":"expo-media-library"}],"name":"Promise","package":"typescript"}}]},{"name":"getMomentsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getMomentsAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"Album"},"name":"Album","package":"expo-media-library"}}],"name":"Promise","package":"typescript"}}]},{"name":"getPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"getPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Checks user's permissions for accessing media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to check write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has\nan effect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"isAvailableAsync","variant":"declaration","kind":64,"signatures":[{"name":"isAvailableAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"migrateAlbumIfNeededAsync","variant":"declaration","kind":64,"signatures":[{"name":"migrateAlbumIfNeededAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPicker","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPicker","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Allows the user to update the assets that your app has access to.\nThe system modal is only displayed if the user originally allowed only "},{"kind":"code","text":"`limited`"},{"kind":"text","text":" access to their\nmedia library, otherwise this method is a no-op."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that either rejects if the method is unavailable, or resolves to "},{"kind":"code","text":"`void`"},{"kind":"text","text":".\n> __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\nThat information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using ["},{"kind":"code","text":"`addListener()`"},{"kind":"text","text":"](#medialibraryaddlistenerlistener).\nIf "},{"kind":"code","text":"`hasIncrementalChanges`"},{"kind":"text","text":" is "},{"kind":"code","text":"`false`"},{"kind":"text","text":", the user changed their permissions."}]},{"tag":"@platform","content":[{"kind":"text","text":"android 14+"}]},{"tag":"@platform","content":[{"kind":"text","text":"ios"}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented."}]},"type":{"type":"array","elementType":{"type":"reference","name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"presentPermissionsPickerAsync","variant":"declaration","kind":64,"signatures":[{"name":"presentPermissionsPickerAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`presentPermissionsPicker()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"mediaTypes","variant":"param","kind":32768,"flags":{"isOptional":true},"type":{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"MediaTypeFilter"},"name":"MediaTypeFilter","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"removeAllListeners","variant":"declaration","kind":64,"signatures":[{"name":"removeAllListeners","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Removes all listeners."}]},"type":{"type":"intrinsic","name":"void"}}]},{"name":"removeAssetsFromAlbumAsync","variant":"declaration","kind":64,"signatures":[{"name":"removeAssetsFromAlbumAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`album.removeAssets()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"assets","variant":"param","kind":32768,"type":{"type":"union","types":[{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"},{"type":"array","elementType":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}}]}},{"name":"album","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AlbumRef"},"name":"AlbumRef","package":"expo-media-library"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"removeSubscription","variant":"declaration","kind":64,"signatures":[{"name":"removeSubscription","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`subscription.remove()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"subscription","variant":"param","kind":32768,"type":{"type":"reference","name":"EventSubscription","package":"expo-modules-core"}}],"type":{"type":"intrinsic","name":"void"}}]},{"name":"requestPermissionsAsync","variant":"declaration","kind":64,"signatures":[{"name":"requestPermissionsAsync","variant":"signature","kind":4096,"comment":{"summary":[{"kind":"text","text":"Asks the user to grant permissions for accessing media in user's media library."}],"blockTags":[{"tag":"@returns","content":[{"kind":"text","text":"A promise that fulfils with ["},{"kind":"code","text":"`PermissionResponse`"},{"kind":"text","text":"](#permissionresponse) object."}]}]},"parameters":[{"name":"writeOnly","variant":"param","kind":32768,"comment":{"summary":[{"kind":"text","text":"Whether to request write-only access without read permissions. Defaults to "},{"kind":"code","text":"`false`"},{"kind":"text","text":"."}]},"type":{"type":"intrinsic","name":"boolean"},"defaultValue":"false"},{"name":"granularPermissions","variant":"param","kind":32768,"flags":{"isOptional":true},"comment":{"summary":[{"kind":"text","text":"A list of ["},{"kind":"code","text":"`GranularPermission`"},{"kind":"text","text":"](#granularpermission) values. This parameter has an\neffect only on Android 13 and newer. By default, "},{"kind":"code","text":"`expo-media-library`"},{"kind":"text","text":" will ask for all possible permissions.\n\n> When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin."}]},"type":{"type":"array","elementType":{"type":"reference","name":"GranularPermission","package":"expo-media-library"}}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"reference","name":"PermissionResponse","package":"expo-modules-core"}],"name":"Promise","package":"typescript"}}]},{"name":"saveToLibraryAsync","variant":"declaration","kind":64,"signatures":[{"name":"saveToLibraryAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`Asset.create()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"localUri","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"string"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"void"}],"name":"Promise","package":"typescript"}}]},{"name":"setAssetFavoriteAsync","variant":"declaration","kind":64,"signatures":[{"name":"setAssetFavoriteAsync","variant":"signature","kind":4096,"comment":{"summary":[],"blockTags":[{"tag":"@deprecated","content":[{"kind":"text","text":"Use "},{"kind":"code","text":"`asset.setFavorite()`"},{"kind":"text","text":" or import this method from "},{"kind":"code","text":"`expo-media-library/legacy`"},{"kind":"text","text":". This method will throw in runtime."}]}]},"parameters":[{"name":"asset","variant":"param","kind":32768,"type":{"type":"reference","target":{"packageName":"expo-media-library","packagePath":"src/legacy/MediaLibrary.ts","qualifiedName":"AssetRef"},"name":"AssetRef","package":"expo-media-library"}},{"name":"isFavorite","variant":"param","kind":32768,"type":{"type":"intrinsic","name":"boolean"}}],"type":{"type":"reference","target":{"packageName":"typescript","packagePath":"lib/lib.es5.d.ts","qualifiedName":"Promise"},"typeArguments":[{"type":"intrinsic","name":"boolean"}],"name":"Promise","package":"typescript"}}]},{"name":"Subscription","variant":"reference","kind":4194304}],"packageName":"expo-media-library"} \ No newline at end of file diff --git a/docs/scripts/agent-instructions.ts b/docs/scripts/agent-instructions.ts index 792bb8fd82a627..819d4dc803b6b2 100644 --- a/docs/scripts/agent-instructions.ts +++ b/docs/scripts/agent-instructions.ts @@ -37,9 +37,9 @@ export function buildAgentInstructions(pathname: string): string { If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved: -curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"${pathname}","feedback":"🤖 Agent feedback for docs: ","model":""}' +curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"${pathname}","feedback":"🤖 Agent feedback for docs: (, )"}' -Only submit when you have something specific and actionable to report. Replace with the model you are running as. +Only submit when you have something specific and actionable to report. Replace with the model you are running as and with the tool you are running in (for example, Claude Code, Cursor, Codex CLI). `; diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt index 0a7abd9a747d2a..9812b2da5103bd 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/AppMetricsModule.kt @@ -14,7 +14,6 @@ import expo.modules.appmetrics.storage.JsDebugSession import expo.modules.appmetrics.storage.JsLogRecord import expo.modules.appmetrics.storage.JsMetric import expo.modules.appmetrics.storage.LogRecord -import expo.modules.appmetrics.storage.Metric import expo.modules.appmetrics.storage.SessionManager import expo.modules.appmetrics.storage.SessionMetricInput import expo.modules.appmetrics.storage.SessionSharedObject @@ -209,7 +208,7 @@ class AppMetricsModule : Module(), UpdatesStateChangeListener { observer.setFilter(filter) } } - + Class("Session", SessionSharedObject::class) { // TODO(@ubax): Allow for user session creation from JS Constructor { -> diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/appstartup/AppStartupManager.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/appstartup/AppStartupManager.kt index 84f4f44e974039..3297870fedf62d 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/appstartup/AppStartupManager.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/appstartup/AppStartupManager.kt @@ -50,8 +50,11 @@ object AppStartupManager { // and the JS thread. @Volatile guarantees writes are visible across threads so the // one-shot guards (hasRecorded*) don't spuriously fire twice. @Volatile private var bundleLoadStartTime: Long? = null + @Volatile private var launchTimeInMillis: Long? = null + @Volatile private var hasRecordedInteractive = false + @Volatile private var hasRecordedFirstRender = false @Volatile diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/networkrequests/NetworkRequestInterceptor.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/networkrequests/NetworkRequestInterceptor.kt index 8fe4370d615a07..11a498e4541ea2 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/networkrequests/NetworkRequestInterceptor.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/networkrequests/NetworkRequestInterceptor.kt @@ -213,7 +213,9 @@ internal fun buildSnapshot( ?: originalRequest.body?.contentLength()?.takeIf { it > 0 } ?: 0L requestHeaderBytes + body - } else null + } else { + null + } val responseBytesReceived: Long? = response?.let { val body = phases?.responseBodyBytes?.takeIf { it > 0 } ?: it.body?.contentLength()?.takeIf { it > 0 } @@ -548,4 +550,3 @@ private fun serializedHeaderBytes(headers: Headers): Long { } return total } - diff --git a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt index e13129c5460e51..69662a7d5fedce 100644 --- a/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt +++ b/packages/expo-app-metrics/android/src/main/java/expo/modules/appmetrics/utils/JsonAny.kt @@ -48,10 +48,11 @@ object JsonAny { is JsonNull -> null is JsonPrimitive -> when { element.isString -> element.content - else -> element.booleanOrNull - ?: element.longOrNull - ?: element.doubleOrNull - ?: element.content + else -> + element.booleanOrNull + ?: element.longOrNull + ?: element.doubleOrNull + ?: element.content } is JsonObject -> element.mapValues { (_, v) -> fromElement(v) } is JsonArray -> element.map { fromElement(it) } diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/GlobalAttributesTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/GlobalAttributesTest.kt index 9d96743622aa77..d17e585d6b53ec 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/GlobalAttributesTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/GlobalAttributesTest.kt @@ -104,5 +104,4 @@ class GlobalAttributesTest { assertEquals(1, merged!!.size) assertEquals("pro", merged["tier"]) } - } diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/appstartup/AppStartupManagerTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/appstartup/AppStartupManagerTest.kt index 22973ee1f01057..2e921e6e0a29df 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/appstartup/AppStartupManagerTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/appstartup/AppStartupManagerTest.kt @@ -20,6 +20,7 @@ class AppStartupManagerTest { val field = AppStartupManager::class.java.getDeclaredField("_metrics").apply { isAccessible = true } + @Suppress("UNCHECKED_CAST") val backing = field.get(AppStartupManager) as MutableList backing.clear() diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt index 66296ca0815bf5..76872e4febade5 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/logevents/AttributeValidationTest.kt @@ -1,7 +1,6 @@ package expo.modules.appmetrics.logevents import org.junit.Assert.assertEquals -import org.junit.Assert.assertNotNull import org.junit.Assert.assertNull import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt index 10bbd9b71bbe48..0d735ff7a2f447 100644 --- a/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt +++ b/packages/expo-app-metrics/android/src/test/java/expo/modules/appmetrics/storage/SessionMappersTest.kt @@ -184,6 +184,7 @@ class SessionMappersTest { // Both should decode the nested user object the same way. @Suppress("UNCHECKED_CAST") val metricUser = metricResult?.get("user") as? Map + @Suppress("UNCHECKED_CAST") val logUser = logResult?.get("user") as? Map assertEquals(metricUser, logUser) diff --git a/packages/expo-app-metrics/ios/AppMetrics.swift b/packages/expo-app-metrics/ios/AppMetrics.swift index c3ffcbc5d0aea4..e9651c207b51a1 100644 --- a/packages/expo-app-metrics/ios/AppMetrics.swift +++ b/packages/expo-app-metrics/ios/AppMetrics.swift @@ -9,12 +9,10 @@ public struct AppMetrics { #if !os(tvOS) static let metricKitSubscriber = MetricKitSubscriber() - /** - Registers the MetricKit subscriber to receive diagnostic and performance payloads. - Even though MetricKit doesn't work on the simulator, it prints some logs (probably once a day) - that are piped to the terminal when using the `expo run:ios` command. - To avoid them, we explicitly don't register the subscriber on the simulator. - */ + /// Registers the MetricKit subscriber to receive diagnostic and performance payloads. + /// Even though MetricKit doesn't work on the simulator, it prints some logs (probably once a day) + /// that are piped to the terminal when using the `expo run:ios` command. + /// To avoid them, we explicitly don't register the subscriber on the simulator. static func registerMetricKitSubscriber() { #if !targetEnvironment(simulator) MXMetricManager.shared.add(metricKitSubscriber) @@ -23,18 +21,18 @@ public struct AppMetrics { } #endif - /** - The shared metrics database, or `nil` in release builds if the database could not be opened even - after a wipe-and-retry. In DEBUG we trap with `assertionFailure` so developers see the failure - immediately; in release we keep the host app running because telemetry should never be - load-bearing for the user's primary work — callers degrade naturally via `?.`. - */ + /// The shared metrics database, or `nil` in release builds if the database could not be opened even + /// after a wipe-and-retry. In DEBUG we trap with `assertionFailure` so developers see the failure + /// immediately; in release we keep the host app running because telemetry should never be + /// load-bearing for the user's primary work — callers degrade naturally via `?.`. @AppMetricsActor static let database: MetricsDatabase? = { do { return try MetricsDatabase.openWipingOnFailure() } catch { - logger.error("[AppMetrics] Failed to open the metrics database after a wipe-and-retry: \(error.localizedDescription). Continuing without persistence — metrics and logs from this launch will be dropped.") + logger.error( + "[AppMetrics] Failed to open the metrics database after a wipe-and-retry: \(error.localizedDescription). Continuing without persistence — metrics and logs from this launch will be dropped." + ) assertionFailure("MetricsDatabase failed to open: \(error)") return nil } @@ -45,47 +43,37 @@ public struct AppMetrics { // MARK: - Read API for downstream consumers (e.g. expo-observe) - /** - Returns metric rows whose `id` is greater than `cursor`, in ascending id order. Consumers persist - the largest seen id and pass it back on subsequent calls to fetch only newer rows. Empty when the - database failed to open. - */ + /// Returns metric rows whose `id` is greater than `cursor`, in ascending id order. Consumers persist + /// the largest seen id and pass it back on subsequent calls to fetch only newer rows. Empty when the + /// database failed to open. @AppMetricsActor public static func getMetrics(afterId cursor: Int64) throws -> [MetricRow] { return try database?.getMetrics(afterId: cursor) ?? [] } - /** - Returns log rows whose `id` is greater than `cursor`, in ascending id order. Empty when the - database failed to open. - */ + /// Returns log rows whose `id` is greater than `cursor`, in ascending id order. Empty when the + /// database failed to open. @AppMetricsActor public static func getLogs(afterId cursor: Int64) throws -> [LogRow] { return try database?.getLogs(afterId: cursor) ?? [] } - /** - Hydrates session rows for the given ids. Used to attach session metadata to a batch of metrics - or logs that have already been read past a cursor. - */ + /// Hydrates session rows for the given ids. Used to attach session metadata to a batch of metrics + /// or logs that have already been read past a cursor. @AppMetricsActor public static func getSessions(ids: [String]) throws -> [SessionRow] { return try database?.getSessions(ids: ids) ?? [] } - /** - The largest metric id currently in the database, or `nil` if the metrics table is empty. - Consumers can compare a persisted dispatch cursor against this to detect that the database was - wiped (or never reached the cursor's value) and reset their cursor accordingly. - */ + /// The largest metric id currently in the database, or `nil` if the metrics table is empty. + /// Consumers can compare a persisted dispatch cursor against this to detect that the database was + /// wiped (or never reached the cursor's value) and reset their cursor accordingly. @AppMetricsActor public static func getMaxMetricId() throws -> Int64? { return try database?.getMaxMetricId() ?? nil } - /** - The largest log id currently in the database, or `nil` if the logs table is empty. - */ + /// The largest log id currently in the database, or `nil` if the logs table is empty. @AppMetricsActor public static func getMaxLogId() throws -> Int64? { return try database?.getMaxLogId() ?? nil @@ -106,47 +94,40 @@ public struct AppMetrics { // MARK: - Main session - /** - The main session that tracks metrics for the entire lifecycle of the app process. - - This session starts when the app launches and continues until the app terminates. - Unlike foreground sessions, there is only one main session per app process. - */ + /// The main session that tracks metrics for the entire lifecycle of the app process. + /// + /// This session starts when the app launches and continues until the app terminates. + /// Unlike foreground sessions, there is only one main session per app process. static let mainSession = MainSession() // MARK: - Foreground session - /** - The currently active foreground session, or `nil` if the app is not in the foreground. - - This session tracks metrics while the app is actively visible to the user. It is created - when the app enters the foreground and cleared when the app enters the background. - */ + /// The currently active foreground session, or `nil` if the app is not in the foreground. + /// + /// This session tracks metrics while the app is actively visible to the user. It is created + /// when the app enters the foreground and cleared when the app enters the background. @AppMetricsActor static internal private(set) var foregroundSession: Session? - /** - Starts a new foreground session, stopping any existing session if one is active. - - This should be called when the app becomes active (enters the foreground). If a previous - foreground session is still running, it will be stopped and finalized before creating the new session. - */ + /// Starts a new foreground session, stopping any existing session if one is active. + /// + /// This should be called when the app becomes active (enters the foreground). If a previous + /// foreground session is still running, it will be stopped and finalized before creating the new session. internal static func startNewForegroundSession() { AppMetricsActor.isolated { if let foregroundSession = Self.foregroundSession { - logger.warn("[AppMetrics] New foreground session started while one was already active. Stopping the old session.") + logger.warn( + "[AppMetrics] New foreground session started while one was already active. Stopping the old session.") foregroundSession.stop() } foregroundSession = ForegroundSession() } } - /** - Stops and finalizes the current foreground session if one is active. - - This should be called when the app enters the background. The session will be stopped, - its metrics finalized, and the session reference cleared. - */ + /// Stops and finalizes the current foreground session if one is active. + /// + /// This should be called when the app enters the background. The session will be stopped, + /// its metrics finalized, and the session reference cleared. internal static func stopForegroundSession() { AppMetricsActor.isolated { foregroundSession?.stop() diff --git a/packages/expo-app-metrics/ios/AppMetricsActor.swift b/packages/expo-app-metrics/ios/AppMetricsActor.swift index 00f6154deafc8b..038575c058c6d5 100644 --- a/packages/expo-app-metrics/ios/AppMetricsActor.swift +++ b/packages/expo-app-metrics/ios/AppMetricsActor.swift @@ -6,19 +6,18 @@ public actor AppMetricsActor: GlobalActor { private init() {} - /** - Executes the given closure isolated to `AppMetricsActor` from an asynchronous context. - */ + /// Executes the given closure isolated to `AppMetricsActor` from an asynchronous context. @discardableResult - public static func isolated(_ action: @AppMetricsActor @escaping () async throws -> T) async throws -> T { + public static func isolated(_ action: @AppMetricsActor @escaping () async throws -> T) async throws -> T + { return try await isolated(action).value } - /** - Executes the given closure isolated to `AppMetricsActor` from a synchronous context. - */ + /// Executes the given closure isolated to `AppMetricsActor` from a synchronous context. @discardableResult - public static func isolated(_ action: @AppMetricsActor @escaping () async throws -> Success) -> Task { + public static func isolated(_ action: @AppMetricsActor @escaping () async throws -> Success) + -> Task + { return Task(name: "ExpoAppMetrics") { return try await action() } diff --git a/packages/expo-app-metrics/ios/AppMetricsAppDelegateSubscriber.swift b/packages/expo-app-metrics/ios/AppMetricsAppDelegateSubscriber.swift index bcdbd235e93bfa..fa94f0f5540b82 100644 --- a/packages/expo-app-metrics/ios/AppMetricsAppDelegateSubscriber.swift +++ b/packages/expo-app-metrics/ios/AppMetricsAppDelegateSubscriber.swift @@ -14,7 +14,9 @@ public class AppMetricsAppDelegateSubscriber: ExpoAppDelegateSubscriber { } } - public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + public func application( + _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { AppMetrics.mainSession.appStartupMonitor.markDidFinishLaunching() return true } diff --git a/packages/expo-app-metrics/ios/AppMetricsModule.swift b/packages/expo-app-metrics/ios/AppMetricsModule.swift index fc2f50732fa2f4..c49e4fee385a06 100644 --- a/packages/expo-app-metrics/ios/AppMetricsModule.swift +++ b/packages/expo-app-metrics/ios/AppMetricsModule.swift @@ -1,6 +1,6 @@ -import Foundation -import ExpoModulesCore import EXUpdatesInterface +import ExpoModulesCore +import Foundation internal let logger = Logger(logHandlers: [createOSLogHandler(category: Logger.EXPO_LOG_CATEGORY)]) @@ -161,9 +161,10 @@ public final class AppMetricsModule: Module, UpdatesStateChangeListener { } } - public func updatesStateDidChange(_ event: [String : Any]) { + public func updatesStateDidChange(_ event: [String: Any]) { if UpdatesStateEvent.fromDict(event)?.type ?? .restart == .downloadCompleteWithUpdate, - let metric = AppMetrics.mainSession.updatesMonitor.downloadTimeMetric(subscription) { + let metric = AppMetrics.mainSession.updatesMonitor.downloadTimeMetric(subscription) + { Task { @AppMetricsActor in AppMetrics.mainSession.updatesMonitor.reportMetric(metric) } diff --git a/packages/expo-app-metrics/ios/AppMetricsUserDefaults.swift b/packages/expo-app-metrics/ios/AppMetricsUserDefaults.swift index 0c07dd014541d5..52dead8d171eb4 100644 --- a/packages/expo-app-metrics/ios/AppMetricsUserDefaults.swift +++ b/packages/expo-app-metrics/ios/AppMetricsUserDefaults.swift @@ -1,16 +1,10 @@ -/** - Class that manages a custom `UserDefaults` database with `"dev.expo.app-metrics"` suite name. - */ +/// Class that manages a custom `UserDefaults` database with `"dev.expo.app-metrics"` suite name. public final class AppMetricsUserDefaults: UserDefaults { - /** - Singleton instance of the user defaults for AppMetrics. - It is not isolated, but UserDefaults is thread-safe. - */ + /// Singleton instance of the user defaults for AppMetrics. + /// It is not isolated, but UserDefaults is thread-safe. nonisolated(unsafe) private static let defaults = AppMetricsUserDefaults() - /** - Enum with keys used within this user defaults database. - */ + /// Enum with keys used within this user defaults database. private enum Keys: String { case lastAppLaunchState case environment diff --git a/packages/expo-app-metrics/ios/AppStartup/AppLaunchState.swift b/packages/expo-app-metrics/ios/AppStartup/AppLaunchState.swift index d2bb0c4765eb9b..6b8c9fbf294619 100644 --- a/packages/expo-app-metrics/ios/AppStartup/AppLaunchState.swift +++ b/packages/expo-app-metrics/ios/AppStartup/AppLaunchState.swift @@ -1,9 +1,7 @@ -/** - A struct containing some app launch information that can be used to detect whether: - 1) it was a cold or warm launch, 2) the device was rebooted, 3) the app was updated. - State of the previous app launch is stored in `AppMetricsUserDefaults.lastAppLaunchState`, - but is overridden with the current state once the app is fully launched. - */ +/// A struct containing some app launch information that can be used to detect whether: +/// 1) it was a cold or warm launch, 2) the device was rebooted, 3) the app was updated. +/// State of the previous app launch is stored in `AppMetricsUserDefaults.lastAppLaunchState`, +/// but is overridden with the current state once the app is fully launched. internal struct AppLaunchState: Codable { var bootTime: TimeInterval = Sysctl.getSystemBootTime() var systemVersion: String = DeviceInfo.current.systemVersion diff --git a/packages/expo-app-metrics/ios/AppStartup/AppStartupMarkers.swift b/packages/expo-app-metrics/ios/AppStartup/AppStartupMarkers.swift index 0f60d197f1b1d5..d642a3b1052f8c 100644 --- a/packages/expo-app-metrics/ios/AppStartup/AppStartupMarkers.swift +++ b/packages/expo-app-metrics/ios/AppStartup/AppStartupMarkers.swift @@ -9,11 +9,9 @@ final class AppStartupMarkers: Sendable { @AppMetricsActor var finishedLaunching: TimeInterval? - /** - Wall-clock companion to `finishedLaunching`. `NetworkRequest.timings.fetchStart` uses `Date` - (not `CACurrentMediaTime`) so summarizing requests over the launch window needs an anchor in - the same domain. - */ + /// Wall-clock companion to `finishedLaunching`. `NetworkRequest.timings.fetchStart` uses `Date` + /// (not `CACurrentMediaTime`) so summarizing requests over the launch window needs an anchor in + /// the same domain. @AppMetricsActor var finishedLaunchingDate: Date? @@ -23,23 +21,19 @@ final class AppStartupMarkers: Sendable { @AppMetricsActor var timeToInteractive: TimeInterval? - /** - Time of loading dylibs and executing static initializers such as Objective-C `load`/`initialize` methods. - This is what happens before the `main` application's function is called. - */ + /// Time of loading dylibs and executing static initializers such as Objective-C `load`/`initialize` methods. + /// This is what happens before the `main` application's function is called. @AppMetricsActor func getLoadTime() -> TimeInterval? { return loadTime } - /** - The launch time consists of: - - load time (see `getLoadTime`) - - `main` function - - creation of application's window or scene (`application:didFinishLaunchingWithOptions:`) - - initialization of the React Native instance - - execution of some lifecycle events from the AppDelegate subscribers - */ + /// The launch time consists of: + /// - load time (see `getLoadTime`) + /// - `main` function + /// - creation of application's window or scene (`application:didFinishLaunchingWithOptions:`) + /// - initialization of the React Native instance + /// - execution of some lifecycle events from the AppDelegate subscribers @AppMetricsActor func getLaunchTime() -> TimeInterval? { if let main, let finishedLaunching { diff --git a/packages/expo-app-metrics/ios/AppStartup/AppStartupMonitoring.swift b/packages/expo-app-metrics/ios/AppStartup/AppStartupMonitoring.swift index 121950af0346fa..3b2b9ee91ae295 100644 --- a/packages/expo-app-metrics/ios/AppStartup/AppStartupMonitoring.swift +++ b/packages/expo-app-metrics/ios/AppStartup/AppStartupMonitoring.swift @@ -147,30 +147,22 @@ final class AppStartupMonitoring: MetricReporter, @unchecked Sendable { // MARK: - AppLaunchType internal enum AppLaunchType: String { - /** - The app is launched from scratch. The system must allocate memory, start a fresh runtime environment, - load the app's code and resources from disk, and initialize its components before rendering the UI. - This is the slowest type of launch and typically occurs after a fresh install, reboot, - or when the OS has killed the app to reclaim memory - */ + /// The app is launched from scratch. The system must allocate memory, start a fresh runtime environment, + /// load the app's code and resources from disk, and initialize its components before rendering the UI. + /// This is the slowest type of launch and typically occurs after a fresh install, reboot, + /// or when the OS has killed the app to reclaim memory case cold - /** - The app's main process is still running in memory, but the UI and navigation state have been torn down. - The system does not need to restart the app process or reinitialize the runtime environment, - but it must recreate the app's interface and restore any preserved state. - This often happens when the app is in a background state and the system has cleared its UI to free up memory. - */ + /// The app's main process is still running in memory, but the UI and navigation state have been torn down. + /// The system does not need to restart the app process or reinitialize the runtime environment, + /// but it must recreate the app's interface and restore any preserved state. + /// This often happens when the app is in a background state and the system has cleared its UI to free up memory. case warm - /** - The system prewarmed the app, partially running its launch sequence in the background before the user opens it. - In this case we can't reliably measure app startup times, so we do not collect these metrics. - */ + /// The system prewarmed the app, partially running its launch sequence in the background before the user opens it. + /// In this case we can't reliably measure app startup times, so we do not collect these metrics. case prewarmed } - /** - Tries to guess what type of launch it was. This most likely does not cover all cases and may sometimes return warm when it was actually cold - */ + /// Tries to guess what type of launch it was. This most likely does not cover all cases and may sometimes return warm when it was actually cold private func getAppLaunchType() -> AppLaunchType { // `ActivePrewarm` flag was set => prewarmed launch if AppLoadTimeProvider.wasPrewarmActive() { diff --git a/packages/expo-app-metrics/ios/CrashReporting/CrashReport.swift b/packages/expo-app-metrics/ios/CrashReporting/CrashReport.swift index 9895966852621e..e70b7383495e25 100644 --- a/packages/expo-app-metrics/ios/CrashReporting/CrashReport.swift +++ b/packages/expo-app-metrics/ios/CrashReporting/CrashReport.swift @@ -1,66 +1,60 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Structured crash report extracted from MetricKit's `MXCrashDiagnostic`. - */ +/// Structured crash report extracted from MetricKit's `MXCrashDiagnostic`. public struct CrashReport: Codable, Sendable { - /** Mach exception type (e.g. EXC_BAD_ACCESS, EXC_CRASH). */ + /// Mach exception type (e.g. EXC_BAD_ACCESS, EXC_CRASH). public let exceptionType: Int? - /** Processor-specific exception code. */ + /// Processor-specific exception code. public let exceptionCode: Int? - /** Unix signal number (e.g. SIGSEGV = 11, SIGABRT = 6). */ + /// Unix signal number (e.g. SIGSEGV = 11, SIGABRT = 6). public let signal: Int? - /** Human-readable description of the termination reason. */ + /// Human-readable description of the termination reason. public let terminationReason: String? - /** Memory region info for bad-access crashes. */ + /// Memory region info for bad-access crashes. public let virtualMemoryRegionInfo: String? - /** Objective-C exception details, available when the crash was caused by an unhandled NSException. */ + /// Objective-C exception details, available when the crash was caused by an unhandled NSException. public let exceptionReason: ExceptionReason? - /** Call stack tree, suitable for off-device symbolication. */ + /// Call stack tree, suitable for off-device symbolication. public let callStackTree: CallStackTree? - /** App version at the time of the crash. */ + /// App version at the time of the crash. public let appVersion: String - /** Timestamp range start of the diagnostic payload. */ + /// Timestamp range start of the diagnostic payload. public let timestampBegin: Date - /** Timestamp range end of the diagnostic payload. */ + /// Timestamp range end of the diagnostic payload. public let timestampEnd: Date - /** - Timestamp at which this device received the diagnostic and constructed the report. - Distinct from `timestampEnd` because MetricKit can deliver historical or backlogged - diagnostics — `ingestedAt` reflects when *we* learned about the crash, not when it - happened. - */ + /// Timestamp at which this device received the diagnostic and constructed the report. + /// Distinct from `timestampEnd` because MetricKit can deliver historical or backlogged + /// diagnostics — `ingestedAt` reflects when *we* learned about the crash, not when it + /// happened. public let ingestedAt: Date - /** - Picks the most likely main session that this crash report belongs to. - - MetricKit only gives us the diagnostic payload's time window (`timestampBegin` to - `timestampEnd`, typically a 24-hour bucket), not an exact crash time. Xcode's - "Simulate MetricKit Payloads" delivers a zero-width window where both timestamps - equal "now," so we can't rely on the session's start time falling inside it. - - 1. Treat each session as the interval `[startDate, endDate ?? .distantFuture]` and - pick sessions that intersect the payload window. Among those, prefer the one - that never finished (`endDate == nil`) — an unfinished main session is a strong - signal of a crash. Otherwise pick the intersecting session with the latest start time. - 2. If nothing intersects *and* the window is zero-width (Xcode-simulated payloads - where intersection is impossible by construction), fall back to the latest - unfinished session overall, then to the latest session by start time. - 3. Otherwise return `nil` — a real payload window that doesn't overlap any session - is genuinely unattributable, and silently misattributing it to the current - session would hide that. - */ + /// Picks the most likely main session that this crash report belongs to. + /// + /// MetricKit only gives us the diagnostic payload's time window (`timestampBegin` to + /// `timestampEnd`, typically a 24-hour bucket), not an exact crash time. Xcode's + /// "Simulate MetricKit Payloads" delivers a zero-width window where both timestamps + /// equal "now," so we can't rely on the session's start time falling inside it. + /// + /// 1. Treat each session as the interval `[startDate, endDate ?? .distantFuture]` and + /// pick sessions that intersect the payload window. Among those, prefer the one + /// that never finished (`endDate == nil`) — an unfinished main session is a strong + /// signal of a crash. Otherwise pick the intersecting session with the latest start time. + /// 2. If nothing intersects *and* the window is zero-width (Xcode-simulated payloads + /// where intersection is impossible by construction), fall back to the latest + /// unfinished session overall, then to the latest session by start time. + /// 3. Otherwise return `nil` — a real payload window that doesn't overlap any session + /// is genuinely unattributable, and silently misattributing it to the current + /// session would hide that. func findMatchingSession(in mainSessions: [SessionRow]) -> SessionRow? { let payloadBegin = timestampBegin.ISO8601Format() let payloadEnd = timestampEnd.ISO8601Format() @@ -89,10 +83,8 @@ public struct CrashReport: Codable, Sendable { return candidates.max(by: { $0.startTimestamp < $1.startTimestamp }) } - /** - Mirrors the shape of `MXCallStackTree.JSONRepresentation()`. Every field is optional so that - silently-renamed or removed Apple fields don't break decoding for the rest of the report. - */ + /// Mirrors the shape of `MXCallStackTree.JSONRepresentation()`. Every field is optional so that + /// silently-renamed or removed Apple fields don't break decoding for the rest of the report. public struct CallStackTree: Codable, Sendable { public let callStacks: [CallStack]? @@ -108,35 +100,31 @@ public struct CrashReport: Codable, Sendable { public let offsetIntoBinaryTextSegment: UInt64? public let sampleCount: Int? public let subFrames: [Frame]? - /** - Resolved symbol from on-device `dladdr` symbolication. Swift and Itanium-ABI C++ - names are demangled; Objective-C selectors and plain C symbols are returned as-is. - `nil` when the binary is not loaded in this process or `dladdr` could not resolve it. - */ + /// Resolved symbol from on-device `dladdr` symbolication. Swift and Itanium-ABI C++ + /// names are demangled; Objective-C selectors and plain C symbols are returned as-is. + /// `nil` when the binary is not loaded in this process or `dladdr` could not resolve it. public let symbol: String? } } - /** - Objective-C exception details from `MXCrashDiagnosticObjectiveCExceptionReason`. - */ + /// Objective-C exception details from `MXCrashDiagnosticObjectiveCExceptionReason`. public struct ExceptionReason: Codable, Sendable { - /** Human-readable exception summary. */ + /// Human-readable exception summary. public let composedMessage: String - /** Exception message template before argument substitution. */ + /// Exception message template before argument substitution. public let formatString: String - /** Arguments substituted into the format string. */ + /// Arguments substituted into the format string. public let arguments: [String] - /** Human-readable exception type (e.g. "NSInvalidArgumentException"). */ + /// Human-readable exception type (e.g. "NSInvalidArgumentException"). public let exceptionType: String - /** Exception class name (e.g. "NSException"). */ + /// Exception class name (e.g. "NSException"). public let className: String - /** Exception name field. */ + /// Exception name field. public let exceptionName: String } } @@ -183,7 +171,8 @@ extension CrashReport: CustomStringConvertible { var lines: [String] = ["[CrashReport] App version: \(appVersion)"] if let exceptionType { - lines.append(" Exception: type=\(exceptionName(for: exceptionType)) code=\(exceptionCode.map(String.init) ?? "unknown")") + lines.append( + " Exception: type=\(exceptionName(for: exceptionType)) code=\(exceptionCode.map(String.init) ?? "unknown")") } if let signal { lines.append(" Signal: \(signalName(for: signal)) (\(signal))") diff --git a/packages/expo-app-metrics/ios/CrashReporting/CrashReportSimulation.swift b/packages/expo-app-metrics/ios/CrashReporting/CrashReportSimulation.swift index 89a694d9d016f4..d1430db128fd41 100644 --- a/packages/expo-app-metrics/ios/CrashReporting/CrashReportSimulation.swift +++ b/packages/expo-app-metrics/ios/CrashReporting/CrashReportSimulation.swift @@ -1,10 +1,8 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Creates a randomized crash report for testing the storage and logging path. - Each call picks a random crash type (e.g. EXC_BAD_ACCESS/SIGSEGV, EXC_CRASH/SIGABRT) - with randomized exception codes, timestamps, call stack tree, and occasionally an ObjC exception reason. - */ +/// Creates a randomized crash report for testing the storage and logging path. +/// Each call picks a random crash type (e.g. EXC_BAD_ACCESS/SIGSEGV, EXC_CRASH/SIGABRT) +/// with randomized exception codes, timestamps, call stack tree, and occasionally an ObjC exception reason. func simulateCrashReport() { let crashes: [(exceptionType: Int, signal: Int, terminationReason: String)] = [ (1, 11, "Namespace SIGNAL, Code 0xb"), @@ -21,7 +19,8 @@ func simulateCrashReport() { exceptionCode: Int.random(in: 0...255), signal: crash.signal, terminationReason: crash.terminationReason, - virtualMemoryRegionInfo: crash.exceptionType == 1 ? "0x\(String(UInt.random(in: 0...0xFFFF), radix: 16)) is not in any region" : nil, + virtualMemoryRegionInfo: crash.exceptionType == 1 + ? "0x\(String(UInt.random(in: 0...0xFFFF), radix: 16)) is not in any region" : nil, exceptionReason: simulateExceptionReason(), callStackTree: simulateCallStackTree(), appVersion: AppInfo.current.appVersion ?? "unknown", @@ -34,9 +33,7 @@ func simulateCrashReport() { } } -/** - Generates a fake call stack tree matching MetricKit's shape. - */ +/// Generates a fake call stack tree matching MetricKit's shape. private func simulateCallStackTree() -> CrashReport.CallStackTree { typealias Frame = CrashReport.CallStackTree.Frame @@ -52,12 +49,14 @@ private func simulateCallStackTree() -> CrashReport.CallStackTree { ) } - let baseAddress = UInt64.random(in: 0x100000000...0x100100000) + let baseAddress = UInt64.random(in: 0x1_0000_0000...0x1_0010_0000) let frames: [Frame] = [ - makeFrame(binary: "ExpoAppMetrics", addressRange: baseAddress + 0x1000...baseAddress + 0x9000, offsetRange: 0x1000...0x9000), - makeFrame(binary: "UIKitCore", addressRange: 0x180000000...0x190000000, offsetRange: 0x10000...0x90000), - makeFrame(binary: "libdispatch.dylib", addressRange: 0x190000000...0x1A0000000, offsetRange: 0x1000...0x5000), - makeFrame(binary: "libsystem_pthread.dylib", addressRange: 0x1A0000000...0x1B0000000, offsetRange: 0x1000...0x3000), + makeFrame( + binary: "ExpoAppMetrics", addressRange: baseAddress + 0x1000...baseAddress + 0x9000, offsetRange: 0x1000...0x9000), + makeFrame(binary: "UIKitCore", addressRange: 0x1_8000_0000...0x1_9000_0000, offsetRange: 0x10000...0x90000), + makeFrame(binary: "libdispatch.dylib", addressRange: 0x1_9000_0000...0x1_A000_0000, offsetRange: 0x1000...0x5000), + makeFrame( + binary: "libsystem_pthread.dylib", addressRange: 0x1_A000_0000...0x1_B000_0000, offsetRange: 0x1000...0x3000), ] return CrashReport.CallStackTree( @@ -67,9 +66,7 @@ private func simulateCallStackTree() -> CrashReport.CallStackTree { ) } -/** - Randomly returns an ObjC exception reason (about half the time) or nil. - */ +/// Randomly returns an ObjC exception reason (about half the time) or nil. private func simulateExceptionReason() -> CrashReport.ExceptionReason? { guard Bool.random() else { return nil diff --git a/packages/expo-app-metrics/ios/CrashReporting/CrashReportSymbolicator.swift b/packages/expo-app-metrics/ios/CrashReporting/CrashReportSymbolicator.swift index 06051bbb237bfe..27779318825081 100644 --- a/packages/expo-app-metrics/ios/CrashReporting/CrashReportSymbolicator.swift +++ b/packages/expo-app-metrics/ios/CrashReporting/CrashReportSymbolicator.swift @@ -3,33 +3,29 @@ import Foundation import MachO -/** - On-device symbolication of MetricKit `CallStackTree` frames using `dladdr`. - - Limitations: - - Only resolves frames from binaries currently loaded in this process. System frames - from a previous launch may not be loaded here, in which case we leave them as-is. - - Swift symbols are demangled via `swift_demangle` (libswiftCore); Itanium-ABI C++ - symbols are demangled via `__cxa_demangle` (libc++abi). Other forms (Obj-C - selectors, plain C) are returned unchanged. - - No source file / line number resolution — those require the dSYM and are not on device. - - Inlined call chains are not recovered for the same reason. - - The address arithmetic: - - MetricKit gives us the absolute address as it was at crash time, plus the offset of that - address into the binary's `__TEXT` segment (`offsetIntoBinaryTextSegment`). The address - we need to feed `dladdr` is the *current process's* address for the same instruction: - - currentAddress = currentLoadAddress(binaryName) + offsetIntoBinaryTextSegment - - Where `currentLoadAddress` is the slide-adjusted address of the binary's first segment - (typically `__TEXT`) in this process. We grab it from the dyld image table. - */ +/// On-device symbolication of MetricKit `CallStackTree` frames using `dladdr`. +/// +/// Limitations: +/// - Only resolves frames from binaries currently loaded in this process. System frames +/// from a previous launch may not be loaded here, in which case we leave them as-is. +/// - Swift symbols are demangled via `swift_demangle` (libswiftCore); Itanium-ABI C++ +/// symbols are demangled via `__cxa_demangle` (libc++abi). Other forms (Obj-C +/// selectors, plain C) are returned unchanged. +/// - No source file / line number resolution — those require the dSYM and are not on device. +/// - Inlined call chains are not recovered for the same reason. +/// +/// The address arithmetic: +/// +/// MetricKit gives us the absolute address as it was at crash time, plus the offset of that +/// address into the binary's `__TEXT` segment (`offsetIntoBinaryTextSegment`). The address +/// we need to feed `dladdr` is the *current process's* address for the same instruction: +/// +/// currentAddress = currentLoadAddress(binaryName) + offsetIntoBinaryTextSegment +/// +/// Where `currentLoadAddress` is the slide-adjusted address of the binary's first segment +/// (typically `__TEXT`) in this process. We grab it from the dyld image table. enum CrashReportSymbolicator { - /** - Annotates each frame in the tree with its resolved symbol, when one is available. - */ + /// Annotates each frame in the tree with its resolved symbol, when one is available. static func symbolicate(_ tree: CrashReport.CallStackTree) -> CrashReport.CallStackTree { // Threads in a crash tree share many leaf frames (RunLoop guts, pthread entry points, // Hermes interpreter trampolines). Memoizing the mangled→demangled mapping for the @@ -67,14 +63,16 @@ enum CrashReportSymbolicator { cache: inout [String: String] ) -> String? { guard let binaryName = frame.binaryName, - let offset = frame.offsetIntoBinaryTextSegment, - let loadAddress = loadedImages[binaryName] else { + let offset = frame.offsetIntoBinaryTextSegment, + let loadAddress = loadedImages[binaryName] + else { return nil } let currentAddress = loadAddress + offset var info = Dl_info() guard dladdr(UnsafeRawPointer(bitPattern: UInt(currentAddress)), &info) != 0, - let symbolPtr = info.dli_sname else { + let symbolPtr = info.dli_sname + else { return nil } let mangled = String(cString: symbolPtr) @@ -86,16 +84,14 @@ enum CrashReportSymbolicator { return resolved } - /** - Demangles a Swift or Itanium-ABI C++ symbol on-device. - - Swift symbols are recognized by their `$s` / `_$s` prefix and demangled via - `swift_demangle` from `libswiftCore.dylib`. C++ symbols are recognized by their - `_Z` / `__Z` prefix and demangled via `__cxa_demangle` from `libc++abi.dylib`. - - Anything else (Objective-C selectors, plain C symbols, already-demangled names) - is returned unchanged. - */ + /// Demangles a Swift or Itanium-ABI C++ symbol on-device. + /// + /// Swift symbols are recognized by their `$s` / `_$s` prefix and demangled via + /// `swift_demangle` from `libswiftCore.dylib`. C++ symbols are recognized by their + /// `_Z` / `__Z` prefix and demangled via `__cxa_demangle` from `libc++abi.dylib`. + /// + /// Anything else (Objective-C selectors, plain C symbols, already-demangled names) + /// is returned unchanged. static func demangle(_ symbol: String) -> String { if symbol.hasPrefix("$s") || symbol.hasPrefix("_$s") { return swiftDemangle(symbol) ?? symbol @@ -108,13 +104,15 @@ enum CrashReportSymbolicator { private static func swiftDemangle(_ symbol: String) -> String? { return symbol.withCString { cstr in - guard let ptr = _swift_demangle( - mangledName: cstr, - mangledNameLength: UInt(strlen(cstr)), - outputBuffer: nil, - outputBufferSize: nil, - flags: 0 - ) else { + guard + let ptr = _swift_demangle( + mangledName: cstr, + mangledNameLength: UInt(strlen(cstr)), + outputBuffer: nil, + outputBufferSize: nil, + flags: 0 + ) + else { return nil } defer { @@ -137,27 +135,26 @@ enum CrashReportSymbolicator { } } - /** - Map from binary name (filename only) to its current load address (slide-adjusted). - - Computed once on first access. The Expo / React Native runtime links everything at - startup and doesn't `dlopen` further, so the dyld image table is effectively constant - for the lifetime of the process — caching it avoids ~500 `String` allocations on every - crash-report ingest. - - Trade-off: a third-party SDK that `dlopen`s a framework after launch (rare but legal — - some MDM/analytics SDKs and `Bundle.load()` of code-bearing bundles do this) will leave - frames from that framework with `symbol: nil` for live `didReceive` deliveries that - land after the dlopen. We accept this — past-payload processing at launch (the common - path) sees the full table, and the alternative (rebuilding per ingest) costs more than - it's worth for a corner case. - */ + /// Map from binary name (filename only) to its current load address (slide-adjusted). + /// + /// Computed once on first access. The Expo / React Native runtime links everything at + /// startup and doesn't `dlopen` further, so the dyld image table is effectively constant + /// for the lifetime of the process — caching it avoids ~500 `String` allocations on every + /// crash-report ingest. + /// + /// Trade-off: a third-party SDK that `dlopen`s a framework after launch (rare but legal — + /// some MDM/analytics SDKs and `Bundle.load()` of code-bearing bundles do this) will leave + /// frames from that framework with `symbol: nil` for live `didReceive` deliveries that + /// land after the dlopen. We accept this — past-payload processing at launch (the common + /// path) sees the full table, and the alternative (rebuilding per ingest) costs more than + /// it's worth for a corner case. private static let loadedImages: [String: UInt64] = { var result: [String: UInt64] = [:] let count = _dyld_image_count() for i in 0..?, @@ -191,6 +189,7 @@ private func _swift_demangle( // linked through `-lc++` in the test_spec / via the C++ standard library). // On success returns a malloc'd C string the caller must `free`, and writes 0 to `status`. // Non-zero status values mean: -1 = OOM, -2 = invalid mangled name, -3 = invalid argument. +// swift-format-ignore: AlwaysUseLowerCamelCase @_silgen_name("__cxa_demangle") private func _cxa_demangle( _ mangledName: UnsafePointer?, diff --git a/packages/expo-app-metrics/ios/CrashReporting/CrashTriggers.swift b/packages/expo-app-metrics/ios/CrashReporting/CrashTriggers.swift index dd6ad4f6e67c1c..9344485bcb37aa 100644 --- a/packages/expo-app-metrics/ios/CrashReporting/CrashTriggers.swift +++ b/packages/expo-app-metrics/ios/CrashReporting/CrashTriggers.swift @@ -2,45 +2,43 @@ import Foundation -/** - Helpers that intentionally crash the app to produce real MetricKit crash diagnostics. - Use only for testing the crash-reporting pipeline. - */ +/// Helpers that intentionally crash the app to produce real MetricKit crash diagnostics. +/// Use only for testing the crash-reporting pipeline. enum CrashTriggers { - /** EXC_BAD_ACCESS / SIGSEGV — dereference a bogus pointer. */ + /// EXC_BAD_ACCESS / SIGSEGV — dereference a bogus pointer. static func badAccess() -> Never { let pointer = UnsafePointer(bitPattern: 0x1)! _ = pointer.pointee fatalError("unreachable") } - /** EXC_CRASH / SIGABRT — Swift fatalError. */ + /// EXC_CRASH / SIGABRT — Swift fatalError. static func fatalErrorCrash() -> Never { fatalError("Intentional fatalError for crash-reporting test") } - /** EXC_ARITHMETIC / SIGFPE — integer divide by zero. */ + /// EXC_ARITHMETIC / SIGFPE — integer divide by zero. static func divideByZero() -> Never { let zero = Int("0")! _ = 1 / zero fatalError("unreachable") } - /** EXC_BAD_INSTRUCTION — force-unwrap nil. */ + /// EXC_BAD_INSTRUCTION — force-unwrap nil. static func forceUnwrapNil() -> Never { let value: Int? = nil _ = value! fatalError("unreachable") } - /** Out-of-bounds array access — also EXC_BAD_INSTRUCTION via Swift's runtime trap. */ + /// Out-of-bounds array access — also EXC_BAD_INSTRUCTION via Swift's runtime trap. static func arrayOutOfBounds() -> Never { let array: [Int] = [] _ = array[5] fatalError("unreachable") } - /** Uncaught Objective-C exception — produces `exceptionReason` in MetricKit. */ + /// Uncaught Objective-C exception — produces `exceptionReason` in MetricKit. static func objcException() -> Never { NSException( name: .invalidArgumentException, @@ -50,7 +48,7 @@ enum CrashTriggers { fatalError("unreachable") } - /** Stack overflow via unbounded recursion. */ + /// Stack overflow via unbounded recursion. static func stackOverflow() -> Never { Self.stackOverflow() } diff --git a/packages/expo-app-metrics/ios/Database/MetricRow+Builder.swift b/packages/expo-app-metrics/ios/Database/MetricRow+Builder.swift index ca321c0c0afc69..08d40b708f4603 100644 --- a/packages/expo-app-metrics/ios/Database/MetricRow+Builder.swift +++ b/packages/expo-app-metrics/ios/Database/MetricRow+Builder.swift @@ -3,14 +3,12 @@ import Foundation extension MetricRow { - /** - Builds a `MetricRow` from a `Metric` and the owning session id. Caller-set global attributes - (`GlobalAttributes.set`) are merged into the metric's `params` here so every metric source — - internal SDK metrics, JS-injected metrics, and the session-stop duration write — picks up - the same enrichment. Per-metric keys win over globals on collision. The merged map is - JSON-encoded into a string column; non-encodable payloads degrade to nil with a logged - warning. - */ + /// Builds a `MetricRow` from a `Metric` and the owning session id. Caller-set global attributes + /// (`GlobalAttributes.set`) are merged into the metric's `params` here so every metric source — + /// internal SDK metrics, JS-injected metrics, and the session-stop duration write — picks up + /// the same enrichment. Per-metric keys win over globals on collision. The merged map is + /// JSON-encoded into a string column; non-encodable payloads degrade to nil with a logged + /// warning. static func from(metric: Metric, sessionId: String) -> MetricRow { let mergedParams = GlobalAttributes.merged(with: metric.params?.value as? [String: Any]) return MetricRow( @@ -27,11 +25,9 @@ extension MetricRow { } extension LogRow { - /** - Builds a `LogRow` from a `LogRecord` and the owning session id. Caller-set global attributes - (`GlobalAttributes.set`) are merged into the log's `attributes` here so every log event picks - up the same enrichment. Per-event keys win over globals on collision. - */ + /// Builds a `LogRow` from a `LogRecord` and the owning session id. Caller-set global attributes + /// (`GlobalAttributes.set`) are merged into the log's `attributes` here so every log event picks + /// up the same enrichment. Per-event keys win over globals on collision. static func from(log: LogRecord, sessionId: String) -> LogRow { let mergedAttributes = GlobalAttributes.merged(with: log.attributes?.value as? [String: Any]) return LogRow( diff --git a/packages/expo-app-metrics/ios/Database/MetricsDatabase.swift b/packages/expo-app-metrics/ios/Database/MetricsDatabase.swift index 80841916e81874..48844e8ed94b86 100644 --- a/packages/expo-app-metrics/ios/Database/MetricsDatabase.swift +++ b/packages/expo-app-metrics/ios/Database/MetricsDatabase.swift @@ -2,25 +2,19 @@ import Foundation -/** - SQLite-backed storage for sessions, metrics, logs and crash reports. - - All read/write methods are isolated to `AppMetricsActor`. The connection is opened with - `SQLITE_OPEN_NOMUTEX`, so SQLite assumes a single caller — actor isolation is what guarantees that. - */ +/// SQLite-backed storage for sessions, metrics, logs and crash reports. +/// +/// All read/write methods are isolated to `AppMetricsActor`. The connection is opened with +/// `SQLITE_OPEN_NOMUTEX`, so SQLite assumes a single caller — actor isolation is what guarantees that. final class MetricsDatabase: Sendable { - /** - Schema version stamped into the database on first open. Bump this whenever the schema or its - semantics change in a way that an older or newer build can't operate on; on a mismatch the - database is wiped and recreated (see `openConnection`). We don't ship migrations yet — the data - is local-only and short-lived, so wiping is preferable to maintaining migration code. - */ + /// Schema version stamped into the database on first open. Bump this whenever the schema or its + /// semantics change in a way that an older or newer build can't operate on; on a mismatch the + /// database is wiped and recreated (see `openConnection`). We don't ship migrations yet — the data + /// is local-only and short-lived, so wiping is preferable to maintaining migration code. static let currentSchemaVersion = 3 - /** - How long a session (and its metrics, logs, crash report) is retained before `init` prunes it. - */ - static let sessionRetention: TimeInterval = 7 * 24 * 60 * 60 // 7 days + /// How long a session (and its metrics, logs, crash report) is retained before `init` prunes it. + static let sessionRetention: TimeInterval = 7 * 24 * 60 * 60 // 7 days let database: SQLiteDatabase @@ -31,18 +25,18 @@ final class MetricsDatabase: Sendable { try self.init(directoryUrl: directoryUrl, fileName: fileName) } - /** - Opens the database, falling back to a wipe-and-retry on the first failure. The retry exists for - the rare case where the on-disk file is corrupted in a way the schema-mismatch path can't detect - (e.g. truncated WAL after a power loss). Throws the second error if the retry also fails — the - caller (`AppMetrics.database`) decides what to do with that. - */ + /// Opens the database, falling back to a wipe-and-retry on the first failure. The retry exists for + /// the rare case where the on-disk file is corrupted in a way the schema-mismatch path can't detect + /// (e.g. truncated WAL after a power loss). Throws the second error if the retry also fails — the + /// caller (`AppMetrics.database`) decides what to do with that. static func openWipingOnFailure(fileName: String = "metrics") throws -> MetricsDatabase { let directoryUrl = try defaultDirectoryUrl() do { return try MetricsDatabase(directoryUrl: directoryUrl, fileName: fileName) } catch { - logger.warn("[AppMetrics] Opening the metrics database failed (\(error.localizedDescription)); wiping the file and retrying.") + logger.warn( + "[AppMetrics] Opening the metrics database failed (\(error.localizedDescription)); wiping the file and retrying." + ) try? removeDatabaseFile(at: directoryUrl.appendingPathComponent("\(fileName).db")) return try MetricsDatabase(directoryUrl: directoryUrl, fileName: fileName) } @@ -60,10 +54,8 @@ final class MetricsDatabase: Sendable { #endif } - /** - Designated initializer. Tests use this overload to point the database at a temporary directory - instead of the user's documents directory. - */ + /// Designated initializer. Tests use this overload to point the database at a temporary directory + /// instead of the user's documents directory. init(directoryUrl: URL, fileName: String = "metrics") throws { self.fileUrl = directoryUrl.appendingPathComponent("\(fileName).db") self.database = try Self.openConnection(fileUrl: fileUrl) @@ -72,15 +64,13 @@ final class MetricsDatabase: Sendable { schedulePruneExpiredSessions() } - /** - Marks any session that was still flagged active when the previous process exited (force-quit, - OOM, crash before `stop()` could run) as inactive. The cutoff is captured before any new session - row is inserted, so the just-launched main session won't be touched: tasks drain on - `AppMetricsActor` in FIFO order, and `Session.init` enqueues its INSERT after this task. - - `weak self` for the same reason as `schedulePruneExpiredSessions` — a transient database can - safely deinit before its scheduled task runs. - */ + /// Marks any session that was still flagged active when the previous process exited (force-quit, + /// OOM, crash before `stop()` could run) as inactive. The cutoff is captured before any new session + /// row is inserted, so the just-launched main session won't be touched: tasks drain on + /// `AppMetricsActor` in FIFO order, and `Session.init` enqueues its INSERT after this task. + /// + /// `weak self` for the same reason as `schedulePruneExpiredSessions` — a transient database can + /// safely deinit before its scheduled task runs. private func scheduleDeactivateOrphanedSessions() { let cutoff = Date.now.ISO8601Format() AppMetricsActor.isolated { [weak self] in @@ -95,15 +85,13 @@ final class MetricsDatabase: Sendable { } } - /** - Dispatches a one-shot prune of retention-expired sessions onto `AppMetricsActor`. Fire-and-forget - from `init` so opening the database isn't slowed by the deletion; subsequent actor-isolated calls - queue behind it and will see the pruned state. - - `weak self` so a database that's been discarded before the task runs (e.g. a transient instance - in a test, or a replaced singleton) doesn't keep its connection alive past its visible lifetime - — running prune against a connection whose file has been wiped trips a libsqlite3 use-after-free. - */ + /// Dispatches a one-shot prune of retention-expired sessions onto `AppMetricsActor`. Fire-and-forget + /// from `init` so opening the database isn't slowed by the deletion; subsequent actor-isolated calls + /// queue behind it and will see the pruned state. + /// + /// `weak self` so a database that's been discarded before the task runs (e.g. a transient instance + /// in a test, or a replaced singleton) doesn't keep its connection alive past its visible lifetime + /// — running prune against a connection whose file has been wiped trips a libsqlite3 use-after-free. private func schedulePruneExpiredSessions() { AppMetricsActor.isolated { [weak self] in guard let self else { @@ -118,12 +106,10 @@ final class MetricsDatabase: Sendable { } } - /** - Opens a connection at `fileUrl`. If the existing database was written by a different schema - version than this build understands, the file (plus WAL/shm sidecars) is deleted and a fresh - empty connection is returned — losing local metrics is preferable to operating on a schema we - can't read or write. - */ + /// Opens a connection at `fileUrl`. If the existing database was written by a different schema + /// version than this build understands, the file (plus WAL/shm sidecars) is deleted and a fresh + /// empty connection is returned — losing local metrics is preferable to operating on a schema we + /// can't read or write. private static func openConnection(fileUrl: URL) throws -> SQLiteDatabase { let mismatchedVersion: Int? do { @@ -132,7 +118,8 @@ final class MetricsDatabase: Sendable { // `database` deinits here, releasing the underlying connection before the file is deleted. } if let mismatchedVersion { - logger.warn(""" + logger.warn( + """ [AppMetrics] Metrics database at \(fileUrl.path) is at schema v\(mismatchedVersion) but \ this build expects v\(currentSchemaVersion); recreating to keep this build functional. """) @@ -141,13 +128,12 @@ final class MetricsDatabase: Sendable { return try SQLiteDatabase(fileUrl: fileUrl) } - /** - Returns the on-disk schema version when it differs from `currentSchemaVersion`, or `nil` when the - file is fresh (no `schema_version` table) or already at the expected version. A fresh file is - handled by `createSchemaIfNeeded`, which stamps the current version on first use. - */ + /// Returns the on-disk schema version when it differs from `currentSchemaVersion`, or `nil` when the + /// file is fresh (no `schema_version` table) or already at the expected version. A fresh file is + /// handled by `createSchemaIfNeeded`, which stamps the current version on first use. private static func mismatchedSchemaVersion(database: borrowing SQLiteDatabase) throws -> Int? { - let tableExists = try database.prepare(""" + let tableExists = try database.prepare( + """ SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'schema_version' LIMIT 1 """) var hasTable = false @@ -163,11 +149,9 @@ final class MetricsDatabase: Sendable { return onDiskVersion == currentSchemaVersion ? nil : onDiskVersion } - /** - Removes the database file along with its WAL/shm sidecars. The caller must ensure no - `SQLiteDatabase` instance for this file is still alive — when one falls out of scope its `deinit` - runs `sqlite3_close_v2`, which is what releases the file handle. - */ + /// Removes the database file along with its WAL/shm sidecars. The caller must ensure no + /// `SQLiteDatabase` instance for this file is still alive — when one falls out of scope its `deinit` + /// runs `sqlite3_close_v2`, which is what releases the file handle. private static func removeDatabaseFile(at fileUrl: URL) throws { let fileManager = FileManager.default let basePath = fileUrl.path @@ -178,12 +162,10 @@ final class MetricsDatabase: Sendable { } } - /** - Schema version recorded in the open database. `nil` only on a freshly created file before - `createSchemaIfNeeded` has stamped a version row — which shouldn't be observable from outside - `init`. Exposed primarily so tests can verify migration behavior without reaching into the - underlying `SQLiteDatabase`. - */ + /// Schema version recorded in the open database. `nil` only on a freshly created file before + /// `createSchemaIfNeeded` has stamped a version row — which shouldn't be observable from outside + /// `init`. Exposed primarily so tests can verify migration behavior without reaching into the + /// underlying `SQLiteDatabase`. @AppMetricsActor var schemaVersion: Int? { return try? Self.readSchemaVersion(database: database) @@ -191,12 +173,11 @@ final class MetricsDatabase: Sendable { // MARK: - Sessions - /** - Inserts a session row, ignoring conflicts on the primary key. - */ + /// Inserts a session row, ignoring conflicts on the primary key. @AppMetricsActor func insert(session: SessionRow) throws { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ INSERT OR IGNORE INTO sessions ( id, type, startTimestamp, endTimestamp, isActive, environment, appName, appIdentifier, appVersion, appBuildNumber, @@ -216,7 +197,7 @@ final class MetricsDatabase: Sendable { session.appName, session.appIdentifier, session.appVersion, session.appBuildNumber, session.appUpdateId, session.appUpdateRuntimeVersion, session.appUpdateRequestHeaders, session.appEasBuildId, session.deviceOs, session.deviceOsVersion, session.deviceModel, session.deviceName, - session.expoSdkVersion, session.reactNativeVersion, session.clientVersion, session.languageTag + session.expoSdkVersion, session.reactNativeVersion, session.clientVersion, session.languageTag, ]) try statement.run() } @@ -234,7 +215,8 @@ final class MetricsDatabase: Sendable { @AppMetricsActor func updateSessionActiveStatus(id: String, isActive: Bool, endTimestamp: String?) throws { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ UPDATE sessions SET isActive = ?1, endTimestamp = ?2 WHERE id = ?3 """) try statement.bindAll([isActive, endTimestamp, id]) @@ -243,7 +225,8 @@ final class MetricsDatabase: Sendable { @AppMetricsActor func deactivateAllSessionsBefore(timestamp: String) throws { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ UPDATE sessions SET isActive = 0 WHERE isActive = 1 AND startTimestamp < ?1 """) try statement.bindAll([timestamp]) @@ -264,18 +247,17 @@ final class MetricsDatabase: Sendable { try statement.run() } - /** - Patches the OTA-related app columns on every active session. Called when the launched-update id - becomes known after the session row has already been written (e.g. an update finishes downloading - mid-session, or `getUpdatesMetricsInfo()` initially returned nil). - */ + /// Patches the OTA-related app columns on every active session. Called when the launched-update id + /// becomes known after the session row has already been written (e.g. an update finishes downloading + /// mid-session, or `getUpdatesMetricsInfo()` initially returned nil). @AppMetricsActor func updateAppUpdatesInfoForActiveSessions( updateId: String?, runtimeVersion: String?, requestHeadersJSON: String? ) throws { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ UPDATE sessions SET appUpdateId = ?1, appUpdateRuntimeVersion = ?2, appUpdateRequestHeaders = ?3 WHERE isActive = 1 @@ -284,11 +266,9 @@ final class MetricsDatabase: Sendable { try statement.run() } - /** - Deletes a session and any crash report keyed by its id. Metrics and logs cascade via FK; crash - reports do not (they're allowed to outlive their session, since a crash can be attributed to a - session we never managed to record). - */ + /// Deletes a session and any crash report keyed by its id. Metrics and logs cascade via FK; crash + /// reports do not (they're allowed to outlive their session, since a crash can be attributed to a + /// session we never managed to record). @AppMetricsActor func deleteSession(id: String) throws { try database.transaction { @@ -307,10 +287,8 @@ final class MetricsDatabase: Sendable { } } - /** - Returns the `main` sessions — newest first — for crash-report attribution. Crashes from past - launches (delivered by MetricKit on a later launch) are matched against these. - */ + /// Returns the `main` sessions — newest first — for crash-report attribution. Crashes from past + /// launches (delivered by MetricKit on a later launch) are matched against these. @AppMetricsActor func getMainSessions() throws -> [SessionRow] { return try collectSessions( @@ -318,19 +296,15 @@ final class MetricsDatabase: Sendable { ) } - /** - Returns the inactive (ended) sessions along with their metrics, logs, and crash report — newest - first. Backs the debug-only `getInactiveSessions` JS API. - */ + /// Returns the inactive (ended) sessions along with their metrics, logs, and crash report — newest + /// first. Backs the debug-only `getInactiveSessions` JS API. @AppMetricsActor func getInactiveSessionsWithChildren() throws -> [SessionWithChildren] { return try getInactiveSessions().compactMap { try getSessionWithChildren(id: $0.id) } } - /** - Returns a single session along with its metrics, logs, and crash report, or `nil` if no session - with that id exists. - */ + /// Returns a single session along with its metrics, logs, and crash report, or `nil` if no session + /// with that id exists. @AppMetricsActor func getSessionWithChildren(id: String) throws -> SessionWithChildren? { guard let session = try getSession(id: id) else { @@ -349,13 +323,12 @@ final class MetricsDatabase: Sendable { ) } - /** - Returns metric rows whose `id` is greater than `cursor`, in ascending id order. Dispatch uses - this with the persisted "last dispatched metric id" cursor to fetch only new rows. - */ + /// Returns metric rows whose `id` is greater than `cursor`, in ascending id order. Dispatch uses + /// this with the persisted "last dispatched metric id" cursor to fetch only new rows. @AppMetricsActor func getMetrics(afterId cursor: Int64) throws -> [MetricRow] { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ SELECT id, sessionId, timestamp, category, name, value, routeName, updateId, params FROM metrics WHERE id > ?1 ORDER BY id ASC """) @@ -367,12 +340,11 @@ final class MetricsDatabase: Sendable { return rows } - /** - Returns log rows whose `id` is greater than `cursor`, in ascending id order. - */ + /// Returns log rows whose `id` is greater than `cursor`, in ascending id order. @AppMetricsActor func getLogs(afterId cursor: Int64) throws -> [LogRow] { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ SELECT id, sessionId, timestamp, severity, name, body, attributes, droppedAttributesCount FROM logs WHERE id > ?1 ORDER BY id ASC """) @@ -384,17 +356,16 @@ final class MetricsDatabase: Sendable { return rows } - /** - Fetches a batch of sessions by id. Used to hydrate session metadata after looking up which - sessions own a set of metric/log rows during dispatch. - */ + /// Fetches a batch of sessions by id. Used to hydrate session metadata after looking up which + /// sessions own a set of metric/log rows during dispatch. @AppMetricsActor func getSessions(ids: [String]) throws -> [SessionRow] { if ids.isEmpty { return [] } let placeholders = ids.indices.map { "?\($0 + 1)" }.joined(separator: ", ") - let statement = try database.prepare(""" + let statement = try database.prepare( + """ SELECT \(sessionColumns) FROM sessions WHERE id IN (\(placeholders)) """) try statement.bindAll(ids.map { $0 as SQLiteBindable }) @@ -407,21 +378,21 @@ final class MetricsDatabase: Sendable { @AppMetricsActor func getAllActiveSessions() throws -> [SessionRow] { - return try collectSessions(sql: """ - SELECT \(sessionColumns) FROM sessions WHERE isActive = 1 ORDER BY startTimestamp DESC - """) + return try collectSessions( + sql: """ + SELECT \(sessionColumns) FROM sessions WHERE isActive = 1 ORDER BY startTimestamp DESC + """) } - /** - Deletes sessions whose start timestamp is older than `cutoff`, regardless of their `isActive` - flag — that flag is unreliable for sessions belonging to a process that crashed before it could - stamp an end timestamp. Metrics and logs cascade via FK; matching crash reports are removed in - the same transaction. - */ + /// Deletes sessions whose start timestamp is older than `cutoff`, regardless of their `isActive` + /// flag — that flag is unreliable for sessions belonging to a process that crashed before it could + /// stamp an end timestamp. Metrics and logs cascade via FK; matching crash reports are removed in + /// the same transaction. @AppMetricsActor func cleanupSessions(olderThan cutoff: String) throws { try database.transaction { - let dropCrashReports = try database.prepare(""" + let dropCrashReports = try database.prepare( + """ DELETE FROM crash_reports WHERE sessionId IN (SELECT id FROM sessions WHERE startTimestamp < ?1) """) @@ -436,19 +407,18 @@ final class MetricsDatabase: Sendable { // MARK: - Metrics - /** - Inserts a single metric and returns its rowid (the auto-incremented `id`). - */ + /// Inserts a single metric and returns its rowid (the auto-incremented `id`). @AppMetricsActor @discardableResult func insert(metric: MetricRow) throws -> Int64 { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ INSERT INTO metrics (sessionId, timestamp, category, name, value, routeName, updateId, params) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) """) try statement.bindAll([ metric.sessionId, metric.timestamp, metric.category, metric.name, - metric.value, metric.routeName, metric.updateId, metric.params + metric.value, metric.routeName, metric.updateId, metric.params, ]) try statement.run() return database.lastInsertRowid() @@ -468,7 +438,8 @@ final class MetricsDatabase: Sendable { @AppMetricsActor func getMetrics(sessionId: String) throws -> [MetricRow] { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ SELECT id, sessionId, timestamp, category, name, value, routeName, updateId, params FROM metrics WHERE sessionId = ?1 ORDER BY id ASC """) @@ -480,11 +451,9 @@ final class MetricsDatabase: Sendable { return rows } - /** - Returns the highest `id` currently in the metrics table, or `nil` if it's empty. Useful for - detecting that an externally-held cursor (e.g. expo-observe's dispatch progress) has fallen out - of sync with the table — usually because the database was wiped on a schema mismatch. - */ + /// Returns the highest `id` currently in the metrics table, or `nil` if it's empty. Useful for + /// detecting that an externally-held cursor (e.g. expo-observe's dispatch progress) has fallen out + /// of sync with the table — usually because the database was wiped on a schema mismatch. @AppMetricsActor func getMaxMetricId() throws -> Int64? { return try selectMaxId(table: "metrics") @@ -495,13 +464,14 @@ final class MetricsDatabase: Sendable { @AppMetricsActor @discardableResult func insert(log: LogRow) throws -> Int64 { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ INSERT INTO logs (sessionId, timestamp, severity, name, body, attributes, droppedAttributesCount) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) """) try statement.bindAll([ log.sessionId, log.timestamp, log.severity, log.name, - log.body, log.attributes, log.droppedAttributesCount + log.body, log.attributes, log.droppedAttributesCount, ]) try statement.run() return database.lastInsertRowid() @@ -521,7 +491,8 @@ final class MetricsDatabase: Sendable { @AppMetricsActor func getLogs(sessionId: String) throws -> [LogRow] { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ SELECT id, sessionId, timestamp, severity, name, body, attributes, droppedAttributesCount FROM logs WHERE sessionId = ?1 ORDER BY id ASC """) @@ -540,16 +511,15 @@ final class MetricsDatabase: Sendable { // MARK: - Crash reports - /** - Stores a crash report payload (caller serializes to JSON), replacing any existing entry for the - given `sessionId`. The session row is *not* required to exist — crashes are sometimes attributed - to a session that was never written (e.g. the app crashed before the session row reached disk). - Such orphan crash reports are removed when the matching session id is later seen and deleted, or - when the database is wiped. - */ + /// Stores a crash report payload (caller serializes to JSON), replacing any existing entry for the + /// given `sessionId`. The session row is *not* required to exist — crashes are sometimes attributed + /// to a session that was never written (e.g. the app crashed before the session row reached disk). + /// Such orphan crash reports are removed when the matching session id is later seen and deleted, or + /// when the database is wiped. @AppMetricsActor func setCrashReport(sessionId: String, payload: String) throws { - let statement = try database.prepare(""" + let statement = try database.prepare( + """ INSERT OR REPLACE INTO crash_reports (sessionId, payload) VALUES (?1, ?2) """) try statement.bindAll([sessionId, payload]) @@ -575,11 +545,9 @@ final class MetricsDatabase: Sendable { // MARK: - Schema - /** - Creates the schema (tables, indexes, version row) atomically. Wrapping the whole bootstrap in a - transaction ensures a process crash mid-init can never leave the database with tables but no - `schema_version` row — which would later be misread as "fresh" and skip migrations. - */ + /// Creates the schema (tables, indexes, version row) atomically. Wrapping the whole bootstrap in a + /// transaction ensures a process crash mid-init can never leave the database with tables but no + /// `schema_version` row — which would later be misread as "fresh" and skip migrations. private func createSchemaIfNeeded() throws { try database.transaction { try createSchemaTables() @@ -591,18 +559,17 @@ final class MetricsDatabase: Sendable { } } - /** - Creates the four data tables plus `schema_version`. Relationships: - - - `sessions` is the root. Every other table keys off `sessions.id` (a UUID string). - - `metrics` and `logs` each have a `sessionId` FK with `ON DELETE CASCADE`. Their `id` is - `INTEGER PRIMARY KEY AUTOINCREMENT` so `expo-observe` can dispatch with a monotonic cursor. - - `crash_reports` is keyed by `sessionId`. There's no FK constraint; the relationship is - informational, and deletes cascade manually (see `deleteSession`, `deleteAllSessions`, - `cleanupSessions`). - */ + /// Creates the four data tables plus `schema_version`. Relationships: + /// + /// - `sessions` is the root. Every other table keys off `sessions.id` (a UUID string). + /// - `metrics` and `logs` each have a `sessionId` FK with `ON DELETE CASCADE`. Their `id` is + /// `INTEGER PRIMARY KEY AUTOINCREMENT` so `expo-observe` can dispatch with a monotonic cursor. + /// - `crash_reports` is keyed by `sessionId`. There's no FK constraint; the relationship is + /// informational, and deletes cascade manually (see `deleteSession`, `deleteAllSessions`, + /// `cleanupSessions`). private func createSchemaTables() throws { - try database.execute(""" + try database.execute( + """ CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL); CREATE TABLE IF NOT EXISTS sessions ( diff --git a/packages/expo-app-metrics/ios/Database/MetricsDatabaseRows.swift b/packages/expo-app-metrics/ios/Database/MetricsDatabaseRows.swift index e5bb5e945b155a..a302127ce3a2fe 100644 --- a/packages/expo-app-metrics/ios/Database/MetricsDatabaseRows.swift +++ b/packages/expo-app-metrics/ios/Database/MetricsDatabaseRows.swift @@ -2,10 +2,8 @@ import Foundation -/** - A session paired with its child metrics, logs, and (optional) crash report payload — the shape - dispatch and the JS bridge consume. - */ +/// A session paired with its child metrics, logs, and (optional) crash report payload — the shape +/// dispatch and the JS bridge consume. struct SessionWithChildren: Sendable { let session: SessionRow let metrics: [MetricRow] @@ -13,10 +11,8 @@ struct SessionWithChildren: Sendable { let crashReportJSON: String? } -/** - Persistence-layer representation of a session row. Mirrors the columns of the `sessions` table - and is intentionally decoupled from the in-memory `Session` class hierarchy. - */ +/// Persistence-layer representation of a session row. Mirrors the columns of the `sessions` table +/// and is intentionally decoupled from the in-memory `Session` class hierarchy. public struct SessionRow: Sendable { public let id: String public let type: String @@ -123,10 +119,8 @@ extension SessionRow { } } -/** - Persistence-layer representation of a metric row. `id` is `nil` for rows that have not yet been - inserted; assigned by SQLite on insert. - */ +/// Persistence-layer representation of a metric row. `id` is `nil` for rows that have not yet been +/// inserted; assigned by SQLite on insert. public struct MetricRow: Sendable { public let id: Int64? public let sessionId: String @@ -136,9 +130,7 @@ public struct MetricRow: Sendable { public let value: Double public let routeName: String? public let updateId: String? - /** - JSON-encoded blob for free-form parameters. The persistence layer doesn't interpret the contents. - */ + /// JSON-encoded blob for free-form parameters. The persistence layer doesn't interpret the contents. public let params: String? public init( @@ -180,9 +172,7 @@ extension MetricRow { } } -/** - Persistence-layer representation of a log row. - */ +/// Persistence-layer representation of a log row. public struct LogRow: Sendable { public let id: Int64? public let sessionId: String @@ -190,9 +180,7 @@ public struct LogRow: Sendable { public let severity: String public let name: String public let body: String? - /** - JSON-encoded attributes blob. The persistence layer doesn't interpret the contents. - */ + /// JSON-encoded attributes blob. The persistence layer doesn't interpret the contents. public let attributes: String? public let droppedAttributesCount: Int diff --git a/packages/expo-app-metrics/ios/Database/SQLiteDatabase.swift b/packages/expo-app-metrics/ios/Database/SQLiteDatabase.swift index 34210a6338642b..263bb4366dc06b 100644 --- a/packages/expo-app-metrics/ios/Database/SQLiteDatabase.swift +++ b/packages/expo-app-metrics/ios/Database/SQLiteDatabase.swift @@ -3,13 +3,11 @@ import Foundation import SQLite3 -/** - Owns a SQLite connection. The non-copyable shape encodes that the underlying C handle is an - exclusive resource — there can never be two `SQLiteDatabase` values referring to the same open - connection — so concurrent access via aliasing is impossible by construction. Callers still need - to serialize access through some single owner (we use `AppMetricsActor`) because the C library's - statement/transaction state is shared per-connection. - */ +/// Owns a SQLite connection. The non-copyable shape encodes that the underlying C handle is an +/// exclusive resource — there can never be two `SQLiteDatabase` values referring to the same open +/// connection — so concurrent access via aliasing is impossible by construction. Callers still need +/// to serialize access through some single owner (we use `AppMetricsActor`) because the C library's +/// statement/transaction state is shared per-connection. struct SQLiteDatabase: ~Copyable, Sendable { // `nonisolated(unsafe)` lets the immutable handle cross isolation boundaries. The pointer itself // is `let`; concurrent access to what it points at is the caller's responsibility (we serialize @@ -61,34 +59,26 @@ struct SQLiteDatabase: ~Copyable, Sendable { sqlite3_close_v2(rawHandle) } - /** - Executes one or more SQL statements with no parameters and no result rows. - */ + /// Executes one or more SQL statements with no parameters and no result rows. func execute(_ sql: String) throws { try Self.execute(sql, on: rawHandle) } - /** - Prepares a statement that can be bound and stepped by the caller. - */ + /// Prepares a statement that can be bound and stepped by the caller. func prepare(_ sql: String) throws -> SQLiteStatement { return try SQLiteStatement(db: rawHandle, sql: sql) } - /** - Returns the rowid of the most recent successful INSERT on this connection — the auto-increment - `id` for tables with an `INTEGER PRIMARY KEY AUTOINCREMENT` column. - */ + /// Returns the rowid of the most recent successful INSERT on this connection — the auto-increment + /// `id` for tables with an `INTEGER PRIMARY KEY AUTOINCREMENT` column. func lastInsertRowid() -> Int64 { return sqlite3_last_insert_rowid(rawHandle) } - /** - Runs `body` inside a transaction, rolling back if it throws. The original error always wins — a - rollback failure is logged but does not replace the cause, since the cause is what the caller - needs to diagnose the failed write. A failed rollback does mean the connection is left in an open - transaction; the next `BEGIN` will report that, which is the right place to notice it. - */ + /// Runs `body` inside a transaction, rolling back if it throws. The original error always wins — a + /// rollback failure is logged but does not replace the cause, since the cause is what the caller + /// needs to diagnose the failed write. A failed rollback does mean the connection is left in an open + /// transaction; the next `BEGIN` will report that, which is the right place to notice it. func transaction(_ body: () throws -> T) throws -> T { try execute("BEGIN") do { diff --git a/packages/expo-app-metrics/ios/Database/SQLiteStatement.swift b/packages/expo-app-metrics/ios/Database/SQLiteStatement.swift index 2a0bfa1aea21e5..9c26883145158c 100644 --- a/packages/expo-app-metrics/ios/Database/SQLiteStatement.swift +++ b/packages/expo-app-metrics/ios/Database/SQLiteStatement.swift @@ -4,11 +4,10 @@ import Foundation import SQLite3 // SQLite expects this sentinel for parameters that need to be copied into its own buffers. +// swift-format-ignore: AlwaysUseLowerCamelCase private let SQLITE_TRANSIENT = unsafeBitCast(OpaquePointer(bitPattern: -1), to: sqlite3_destructor_type.self) -/** - A prepared SQLite statement. Reset and finalized automatically when the wrapper is destroyed. - */ +/// A prepared SQLite statement. Reset and finalized automatically when the wrapper is destroyed. final class SQLiteStatement { private let db: OpaquePointer private var handle: OpaquePointer? @@ -73,9 +72,7 @@ final class SQLiteStatement { } } - /** - Binds a sequence of values starting at index 1. Convenience for short, position-based queries. - */ + /// Binds a sequence of values starting at index 1. Convenience for short, position-based queries. func bindAll(_ values: [SQLiteBindable?]) throws { for (offset, value) in values.enumerated() { try value?.bind(to: self, at: Int32(offset + 1)) ?? bind(nil as String?, at: Int32(offset + 1)) @@ -84,9 +81,7 @@ final class SQLiteStatement { // MARK: - Execution - /** - Steps the statement to completion, ignoring any rows. Use for INSERT/UPDATE/DELETE. - */ + /// Steps the statement to completion, ignoring any rows. Use for INSERT/UPDATE/DELETE. func run() throws { let result = sqlite3_step(handle) if result != SQLITE_DONE && result != SQLITE_ROW { @@ -94,9 +89,7 @@ final class SQLiteStatement { } } - /** - Steps the statement and yields each row to the closure. Use for SELECT. - */ + /// Steps the statement and yields each row to the closure. Use for SELECT. func forEachRow(_ body: (SQLiteRow) throws -> Void) throws { while true { let result = sqlite3_step(handle) @@ -112,9 +105,7 @@ final class SQLiteStatement { } } -/** - A type that can be bound as a SQLite parameter. - */ +/// A type that can be bound as a SQLite parameter. protocol SQLiteBindable { func bind(to statement: SQLiteStatement, at index: Int32) throws } @@ -149,9 +140,7 @@ extension Double: SQLiteBindable { } } -/** - Read-only view of one row of a stepped statement. - */ +/// Read-only view of one row of a stepped statement. struct SQLiteRow { let handle: OpaquePointer? diff --git a/packages/expo-app-metrics/ios/Database/SessionRow+Builder.swift b/packages/expo-app-metrics/ios/Database/SessionRow+Builder.swift index d9481d1a318f12..26b76ee8b55aaa 100644 --- a/packages/expo-app-metrics/ios/Database/SessionRow+Builder.swift +++ b/packages/expo-app-metrics/ios/Database/SessionRow+Builder.swift @@ -3,11 +3,9 @@ import Foundation extension SessionRow { - /** - Builds a `SessionRow` from a `Session`, snapshotting the current `AppInfo`, `DeviceInfo` and - environment. Called when a new session is inserted; subsequent updates (end timestamp, environment - patch, OTA app-info patch) are applied with the more focused DAO methods. - */ + /// Builds a `SessionRow` from a `Session`, snapshotting the current `AppInfo`, `DeviceInfo` and + /// environment. Called when a new session is inserted; subsequent updates (end timestamp, environment + /// patch, OTA app-info patch) are applied with the more focused DAO methods. static func snapshot(of session: Session, environment: String?) -> SessionRow { let app = AppInfo.current let device = DeviceInfo.current diff --git a/packages/expo-app-metrics/ios/FrameRate/FrameMetricsRecorder.swift b/packages/expo-app-metrics/ios/FrameRate/FrameMetricsRecorder.swift index f6e74721373c88..ed05a69587acf9 100644 --- a/packages/expo-app-metrics/ios/FrameRate/FrameMetricsRecorder.swift +++ b/packages/expo-app-metrics/ios/FrameRate/FrameMetricsRecorder.swift @@ -1,11 +1,9 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - A lightweight recorder that accumulates frame rate metrics independently. - Multiple recorders can be active simultaneously (e.g., one for the main session, one per screen), - each tracking its own metrics. Call `start()` to begin recording and `stop()` to finish - and retrieve the accumulated metrics. - */ +/// A lightweight recorder that accumulates frame rate metrics independently. +/// Multiple recorders can be active simultaneously (e.g., one for the main session, one per screen), +/// each tracking its own metrics. Call `start()` to begin recording and `stop()` to finish +/// and retrieve the accumulated metrics. public final class FrameMetricsRecorder: Sendable { @AppMetricsActor public private(set) var metrics: FrameRateMetrics = .zero @@ -44,13 +42,15 @@ public final class FrameMetricsRecorder: Sendable { let fpsIsChanging = !frame.equal(duration: previousFrame.duration) || !frame.equal(duration: frame.targetDuration) - let noMoreThanOneFrameDropped = actualFrameDuration < 2 * frame.targetDuration + FrameRateMetrics.refreshRateDurationThreshold + let noMoreThanOneFrameDropped = + actualFrameDuration < 2 * frame.targetDuration + FrameRateMetrics.refreshRateDurationThreshold if fpsIsChanging && noMoreThanOneFrameDropped { actualFrameDuration = frame.targetDuration } - metrics = metrics + FrameRateMetrics.metrics(frameDuration: actualFrameDuration, targetDuration: frame.targetDuration) + metrics = + metrics + FrameRateMetrics.metrics(frameDuration: actualFrameDuration, targetDuration: frame.targetDuration) previousFrame = frame } } diff --git a/packages/expo-app-metrics/ios/FrameRate/FrameRateMetrics.swift b/packages/expo-app-metrics/ios/FrameRate/FrameRateMetrics.swift index 0df94656598c06..e7fbeb3e757528 100644 --- a/packages/expo-app-metrics/ios/FrameRate/FrameRateMetrics.swift +++ b/packages/expo-app-metrics/ios/FrameRate/FrameRateMetrics.swift @@ -11,19 +11,13 @@ public struct FrameRateMetrics: Metrics, CustomStringConvertible, Equatable, Sen public static let category: Metric.Category? = .frameRate - /** - Threshold in seconds to recognize a frame as slow. - */ + /// Threshold in seconds to recognize a frame as slow. private static let slowFrameThreshold: TimeInterval = 0.017 - /** - Threshold in seconds to recognize a frame as frozen. - */ + /// Threshold in seconds to recognize a frame as frozen. private static let frozenFrameThreshold: TimeInterval = 0.7 - /** - Threshold below which a frame is still considered as valid, i.e. rendered in time. - */ + /// Threshold below which a frame is still considered as valid, i.e. rendered in time. static let refreshRateDurationThreshold: TimeInterval = 0.001 let renderedFrames: UInt @@ -34,9 +28,7 @@ public struct FrameRateMetrics: Metrics, CustomStringConvertible, Equatable, Sen let freezeTime: TimeInterval let sessionDuration: TimeInterval - /** - Frozen frames divided by the number of rendered frames. - */ + /// Frozen frames divided by the number of rendered frames. var frozenFramesRatio: Double { guard renderedFrames > 0 else { return 0.0 @@ -44,9 +36,7 @@ public struct FrameRateMetrics: Metrics, CustomStringConvertible, Equatable, Sen return Double(frozenFrames) / Double(renderedFrames) } - /** - Slow frames divided by the number of rendered frames. - */ + /// Slow frames divided by the number of rendered frames. var slowFramesRatio: Double { guard renderedFrames > 0 else { return 0.0 @@ -54,9 +44,7 @@ public struct FrameRateMetrics: Metrics, CustomStringConvertible, Equatable, Sen return Double(slowFrames) / Double(renderedFrames) } - /** - Dropped frames divided by expected frames. - */ + /// Dropped frames divided by expected frames. var droppedFramesRatio: Double { guard expectedFrames > 0 else { return 0.0 @@ -66,14 +54,14 @@ public struct FrameRateMetrics: Metrics, CustomStringConvertible, Equatable, Sen public var description: String { return """ -FrameRateMetrics { - \(expectedFrames) expected, - \(renderedFrames) rendered, - \(droppedFrames) dropped, - \(slowFrames) slow, - \(frozenFrames) frozen -} -""" + FrameRateMetrics { + \(expectedFrames) expected, + \(renderedFrames) rendered, + \(droppedFrames) dropped, + \(slowFrames) slow, + \(frozenFrames) frozen + } + """ } // MARK: - Encodable @@ -103,7 +91,8 @@ FrameRateMetrics { } static func metrics(frameDuration: TimeInterval, targetDuration: TimeInterval) -> FrameRateMetrics { - let expectedFrames, droppedFrames: UInt + let expectedFrames: UInt + let droppedFrames: UInt if frameDuration > (targetDuration + refreshRateDurationThreshold) { expectedFrames = UInt(round(frameDuration / targetDuration)) diff --git a/packages/expo-app-metrics/ios/FrameRate/FrameRateMonitor.swift b/packages/expo-app-metrics/ios/FrameRate/FrameRateMonitor.swift index 44063e41294592..5be1af2b36b6c7 100644 --- a/packages/expo-app-metrics/ios/FrameRate/FrameRateMonitor.swift +++ b/packages/expo-app-metrics/ios/FrameRate/FrameRateMonitor.swift @@ -1,10 +1,8 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - A singleton monitor that owns the display link and fans out frame updates - to all registered `FrameMetricsRecorder` instances. The display link is - automatically started when the first recorder is added and stopped when the last is removed. - */ +/// A singleton monitor that owns the display link and fans out frame updates +/// to all registered `FrameMetricsRecorder` instances. The display link is +/// automatically started when the first recorder is added and stopped when the last is removed. @AppMetricsActor final class FrameRateMonitor: FrameRateObserverDelegate, Sendable { static let shared = FrameRateMonitor() diff --git a/packages/expo-app-metrics/ios/GlobalAttributes.swift b/packages/expo-app-metrics/ios/GlobalAttributes.swift index 0e4f4d18352ea0..311e3980b09739 100644 --- a/packages/expo-app-metrics/ios/GlobalAttributes.swift +++ b/packages/expo-app-metrics/ios/GlobalAttributes.swift @@ -2,26 +2,22 @@ import ExpoModulesCore -/** - Holds caller-provided global attributes that are merged into every subsequent - metric's `params` and log record's `attributes`. Values live for the - lifetime of the SDK instance and are cleared on app restart — persistent - storage is intentionally out of scope. - - The store is guarded by a `Mutex` so it can be read from the JS thread, - the `AppMetricsActor`-driven persistence path, and the SDK's metric - producers without contention. - */ +/// Holds caller-provided global attributes that are merged into every subsequent +/// metric's `params` and log record's `attributes`. Values live for the +/// lifetime of the SDK instance and are cleared on app restart — persistent +/// storage is intentionally out of scope. +/// +/// The store is guarded by a `Mutex` so it can be read from the JS thread, +/// the `AppMetricsActor`-driven persistence path, and the SDK's metric +/// producers without contention. public enum GlobalAttributes { private static let store = Mutex<[String: Any]>([:]) - /** - Replaces the current set of global attributes. The input is sanitized using - the same rules as per-event attributes (`expo.*` reserved, empty keys - rejected, per-record cap). - - Passing an empty map or `nil` clears the store. - */ + /// Replaces the current set of global attributes. The input is sanitized using + /// the same rules as per-event attributes (`expo.*` reserved, empty keys + /// rejected, per-record cap). + /// + /// Passing an empty map or `nil` clears the store. public static func set(_ attributes: [String: Any]?) { let sanitized = sanitizeLogEventAttributes(attributes) store.withLock { state in @@ -29,11 +25,9 @@ public enum GlobalAttributes { } } - /** - Returns the current global attributes merged with the given per-event - attributes. Per-event keys win on collision so callers can override a - global value for a single record without mutating the store. - */ + /// Returns the current global attributes merged with the given per-event + /// attributes. Per-event keys win on collision so callers can override a + /// global value for a single record without mutating the store. static func merged(with eventAttributes: [String: Any]?) -> [String: Any]? { return store.withLock { state in if state.isEmpty { diff --git a/packages/expo-app-metrics/ios/LogEvents/AttributeValidation.swift b/packages/expo-app-metrics/ios/LogEvents/AttributeValidation.swift index d0290bdcba40a0..c1786718300cb2 100644 --- a/packages/expo-app-metrics/ios/LogEvents/AttributeValidation.swift +++ b/packages/expo-app-metrics/ios/LogEvents/AttributeValidation.swift @@ -1,56 +1,48 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Patterns that match attribute keys reserved by the SDK. Caller-provided - attributes whose key matches any of these are dropped: - - - The `expo.*` namespace, owned entirely by the SDK (e.g. `expo.app.name`, - `expo.eas_client.id`). - - Specific OTel Semantic Convention keys the SDK sets on every record - (e.g. `session.id`, `event.name`). Letting callers set these would - produce duplicate-attribute errors on the collector. - - `Regex` isn't Sendable, but the values are constructed once and - never mutated, so sharing them across isolation domains is safe — hence - `nonisolated(unsafe)`. - */ +/// Patterns that match attribute keys reserved by the SDK. Caller-provided +/// attributes whose key matches any of these are dropped: +/// +/// - The `expo.*` namespace, owned entirely by the SDK (e.g. `expo.app.name`, +/// `expo.eas_client.id`). +/// - Specific OTel Semantic Convention keys the SDK sets on every record +/// (e.g. `session.id`, `event.name`). Letting callers set these would +/// produce duplicate-attribute errors on the collector. +/// +/// `Regex` isn't Sendable, but the values are constructed once and +/// never mutated, so sharing them across isolation domains is safe — hence +/// `nonisolated(unsafe)`. nonisolated(unsafe) private let reservedAttributePatterns: [Regex] = [ /^expo\..+/, /^session\.id$/, - /^event\.name$/ + /^event\.name$/, ] -/** - Maximum number of attributes accepted per log record. Mirrors the OTel SDK - default — collectors and backends start to push back well before this limit, - so we cap eagerly and surface the overflow via `droppedAttributesCount`. - */ +/// Maximum number of attributes accepted per log record. Mirrors the OTel SDK +/// default — collectors and backends start to push back well before this limit, +/// so we cap eagerly and surface the overflow via `droppedAttributesCount`. private let maxAttributeCount = 128 -/** - Result of sanitizing caller-provided log-event attributes. - - - `attributes`: the attributes that survived validation, or `nil` when the - input was `nil` or every entry was dropped. - - `droppedCount`: number of attributes that were dropped during validation. - Surfaced on the OTel wire as `droppedAttributesCount` so backends know the - record was filtered. - */ +/// Result of sanitizing caller-provided log-event attributes. +/// +/// - `attributes`: the attributes that survived validation, or `nil` when the +/// input was `nil` or every entry was dropped. +/// - `droppedCount`: number of attributes that were dropped during validation. +/// Surfaced on the OTel wire as `droppedAttributesCount` so backends know the +/// record was filtered. struct SanitizedLogAttributes { let attributes: [String: Any]? let droppedCount: Int } -/** - Filters caller-provided log-event attributes. Drops: - - - keys that are empty after trimming whitespace, - - keys under the reserved `expo.*` namespace or matching SDK-set keys, - - everything past the per-record attribute count cap. - - Each rule warns with its own message so the developer can tell at a glance - which rule fired. - */ +/// Filters caller-provided log-event attributes. Drops: +/// +/// - keys that are empty after trimming whitespace, +/// - keys under the reserved `expo.*` namespace or matching SDK-set keys, +/// - everything past the per-record attribute count cap. +/// +/// Each rule warns with its own message so the developer can tell at a glance +/// which rule fired. func sanitizeLogEventAttributes(_ attributes: [String: Any]?) -> SanitizedLogAttributes { guard let attributes else { return SanitizedLogAttributes(attributes: nil, droppedCount: 0) diff --git a/packages/expo-app-metrics/ios/LogEvents/EventBodyValidation.swift b/packages/expo-app-metrics/ios/LogEvents/EventBodyValidation.swift index 6ac2e58b0383e1..96c43d3741c641 100644 --- a/packages/expo-app-metrics/ios/LogEvents/EventBodyValidation.swift +++ b/packages/expo-app-metrics/ios/LogEvents/EventBodyValidation.swift @@ -1,24 +1,18 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Maximum length of a log event body in characters. Bodies longer than this are - truncated rather than dropped, preserving the prefix (most useful for "what - happened") and appending an ellipsis suffix so consumers can tell the value - was cut. Mirrors the OTel `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` default. - */ +/// Maximum length of a log event body in characters. Bodies longer than this are +/// truncated rather than dropped, preserving the prefix (most useful for "what +/// happened") and appending an ellipsis suffix so consumers can tell the value +/// was cut. Mirrors the OTel `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` default. private let maxEventBodyLength = 4096 -/** - Suffix appended to truncated bodies. Single character so the prefix stays - close to the original length budget. - */ +/// Suffix appended to truncated bodies. Single character so the prefix stays +/// close to the original length budget. private let truncationSuffix = "…" -/** - Truncates a caller-provided log event body to `maxEventBodyLength` characters, - logging a warning when truncation happens. Returns `nil` for `nil` input so - the call site can pass the result through unchanged. - */ +/// Truncates a caller-provided log event body to `maxEventBodyLength` characters, +/// logging a warning when truncation happens. Returns `nil` for `nil` input so +/// the call site can pass the result through unchanged. func validateEventBody(_ body: String?) -> String? { guard let body else { return nil diff --git a/packages/expo-app-metrics/ios/LogEvents/EventNameValidation.swift b/packages/expo-app-metrics/ios/LogEvents/EventNameValidation.swift index 5d014f9cf24730..33b1295dc74205 100644 --- a/packages/expo-app-metrics/ios/LogEvents/EventNameValidation.swift +++ b/packages/expo-app-metrics/ios/LogEvents/EventNameValidation.swift @@ -1,25 +1,19 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Prefix reserved for internal Expo event names. Callers cannot use it so SDK-emitted - events stay distinguishable from app-emitted ones in the backend. - */ +/// Prefix reserved for internal Expo event names. Callers cannot use it so SDK-emitted +/// events stay distinguishable from app-emitted ones in the backend. private let reservedEventNamePrefix = "expo." -/** - Maximum length of a log event name in characters. Names beyond this length are - dropped with a warning — most log backends balk on very long names and a runaway - template literal can easily blow past a few hundred characters by accident. - */ +/// Maximum length of a log event name in characters. Names beyond this length are +/// dropped with a warning — most log backends balk on very long names and a runaway +/// template literal can easily blow past a few hundred characters by accident. private let maxEventNameLength = 256 -/** - Validates and normalizes a caller-provided log event name. - - Returns the trimmed name on success, or `nil` when the name should be rejected. - In the rejection case, a warning is logged explaining why so the developer can - fix the call site without the app crashing over a telemetry concern. - */ +/// Validates and normalizes a caller-provided log event name. +/// +/// Returns the trimmed name on success, or `nil` when the name should be rejected. +/// In the rejection case, a warning is logged explaining why so the developer can +/// fix the call site without the app crashing over a telemetry concern. func validateEventName(_ name: String) -> String? { let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) if trimmedName.isEmpty { diff --git a/packages/expo-app-metrics/ios/LogEvents/LogEventOptions.swift b/packages/expo-app-metrics/ios/LogEvents/LogEventOptions.swift index 1686bb026868bb..55ca36609c6726 100644 --- a/packages/expo-app-metrics/ios/LogEvents/LogEventOptions.swift +++ b/packages/expo-app-metrics/ios/LogEvents/LogEventOptions.swift @@ -2,11 +2,9 @@ import ExpoModulesCore -/** - Options accepted by the `logEvent` module function. The event name is - passed as a separate positional argument and is therefore not part of this - record. - */ +/// Options accepted by the `logEvent` module function. The event name is +/// passed as a separate positional argument and is therefore not part of this +/// record. struct LogEventOptions: Record { @Field var body: String? @Field var attributes: [String: Any]? diff --git a/packages/expo-app-metrics/ios/LogEvents/LogRecord.swift b/packages/expo-app-metrics/ios/LogEvents/LogRecord.swift index 9854a5aad80a1a..67ceab921da72d 100644 --- a/packages/expo-app-metrics/ios/LogEvents/LogRecord.swift +++ b/packages/expo-app-metrics/ios/LogEvents/LogRecord.swift @@ -1,23 +1,17 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - A single log event collected during a session. Records of this shape are - persisted in the local storage and exposed to consumers (e.g. `expo-observe`) - that decide how to dispatch or display them. - */ +/// A single log event collected during a session. Records of this shape are +/// persisted in the local storage and exposed to consumers (e.g. `expo-observe`) +/// that decide how to dispatch or display them. public struct LogRecord: Codable, Sendable { public let name: String public let body: String? public let attributes: AnyCodable? - /** - Number of attributes the SDK dropped while accepting this record (caller - tried to use a reserved key, exceeded the per-record cap, etc.). Consumers - may choose to forward this count to whatever ingest format they target. - */ + /// Number of attributes the SDK dropped while accepting this record (caller + /// tried to use a reserved key, exceeded the per-record cap, etc.). Consumers + /// may choose to forward this count to whatever ingest format they target. public let droppedAttributesCount: Int - /** - Severity of the event. - */ + /// Severity of the event. public let severity: Severity public var timestamp: String = Date.now.ISO8601Format() diff --git a/packages/expo-app-metrics/ios/LogEvents/Severity.swift b/packages/expo-app-metrics/ios/LogEvents/Severity.swift index b2d068b3798e8d..92dbd4efb9c660 100644 --- a/packages/expo-app-metrics/ios/LogEvents/Severity.swift +++ b/packages/expo-app-metrics/ios/LogEvents/Severity.swift @@ -2,17 +2,13 @@ import ExpoModulesCore -/** - Severity of a log event. Each case carries its OpenTelemetry severity number - via `severityNumber` and is sent as `severityText` (uppercased) on the wire. - */ +/// Severity of a log event. Each case carries its OpenTelemetry severity number +/// via `severityNumber` and is sent as `severityText` (uppercased) on the wire. public enum Severity: String, Codable, Sendable, Enumerable { case trace, debug, info, warn, error, fatal - /** - OpenTelemetry severity number that matches this case. - See https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber. - */ + /// OpenTelemetry severity number that matches this case. + /// See https://opentelemetry.io/docs/specs/otel/logs/data-model/#field-severitynumber. public var severityNumber: Int { switch self { case .trace: @@ -30,9 +26,7 @@ public enum Severity: String, Codable, Sendable, Enumerable { } } - /** - Severity text suitable for the OpenTelemetry `severityText` field. - */ + /// Severity text suitable for the OpenTelemetry `severityText` field. public var severityText: String { return rawValue.uppercased() } diff --git a/packages/expo-app-metrics/ios/Memory/MemoryMonitoring.swift b/packages/expo-app-metrics/ios/Memory/MemoryMonitoring.swift index b19f3472d08b9e..eec1631221aa38 100644 --- a/packages/expo-app-metrics/ios/Memory/MemoryMonitoring.swift +++ b/packages/expo-app-metrics/ios/Memory/MemoryMonitoring.swift @@ -1,12 +1,8 @@ struct MemoryMonitoringData: Sendable { - /** - Total number of memory warnings sent by the system. - */ + /// Total number of memory warnings sent by the system. var warningsCount: Int = .zero - /** - Snapshot of the memory usage taken while the last memory warning occurred. - */ + /// Snapshot of the memory usage taken while the last memory warning occurred. var lastMemoryUsageSnapshot: MemoryUsageSnapshot? = nil } diff --git a/packages/expo-app-metrics/ios/Memory/MemoryUsageSnapshot.swift b/packages/expo-app-metrics/ios/Memory/MemoryUsageSnapshot.swift index b47657923eacc3..6498f936f17fbf 100644 --- a/packages/expo-app-metrics/ios/Memory/MemoryUsageSnapshot.swift +++ b/packages/expo-app-metrics/ios/Memory/MemoryUsageSnapshot.swift @@ -25,12 +25,12 @@ struct MemoryUsageSnapshot: Metrics, CustomStringConvertible, Sendable { var description: String { return """ -MemoryUsageSnapshot { - \(memoryFootprint.formatted(.byteCount(style: .memory))) allocated, - \(residentSize.formatted(.byteCount(style: .memory))) physical, - \(freeMemory.formatted(.byteCount(style: .memory))) available -} -""" + MemoryUsageSnapshot { + \(memoryFootprint.formatted(.byteCount(style: .memory))) allocated, + \(residentSize.formatted(.byteCount(style: .memory))) physical, + \(freeMemory.formatted(.byteCount(style: .memory))) available + } + """ } // MARK: - Statics @@ -55,8 +55,12 @@ MemoryUsageSnapshot { } private static func getMemoryFootprint() -> UInt { - let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout.size / MemoryLayout.size) - let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout.size) + // swift-format-ignore: AlwaysUseLowerCamelCase + let TASK_VM_INFO_COUNT = mach_msg_type_number_t( + MemoryLayout.size / MemoryLayout.size) + // swift-format-ignore: AlwaysUseLowerCamelCase + let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t( + MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout.size) var info = task_vm_info_data_t() var count = TASK_VM_INFO_COUNT let kerr = withUnsafeMutablePointer(to: &info) { infoPtr in diff --git a/packages/expo-app-metrics/ios/Metric.swift b/packages/expo-app-metrics/ios/Metric.swift index 459462d0d5d607..f9b40ddd142c00 100644 --- a/packages/expo-app-metrics/ios/Metric.swift +++ b/packages/expo-app-metrics/ios/Metric.swift @@ -1,9 +1,7 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - A struct that represents a single metric which consists of a category, name, value and its creation timestamp. - Metrics stored in the local storage are of this form. - */ +/// A struct that represents a single metric which consists of a category, name, value and its creation timestamp. +/// Metrics stored in the local storage are of this form. public struct Metric: Codable, Sendable { public enum Category: String, Codable, CaseIterable, Sendable { case appStartup @@ -13,7 +11,7 @@ public struct Metric: Codable, Sendable { case updates case navigation // TODO(@ubax): support arbitrary user-defined string categories from JS; - // Until then `JsMetric.toMetric()` drops the category when the raw string + // Until then `JsMetric.toMetric()` drops the category when the raw string // doesn't match a case here. } @@ -24,11 +22,9 @@ public struct Metric: Codable, Sendable { public var routeName: String? = nil public var updateId: String? = nil public var params: AnyCodable? = nil - /** - ID of the session this metric is attached to. `nil` until the metric is handed to a session - (`Session.receiveMetric`) or hydrated from the database — at every JS-observable read path the - field is populated, so consumers can rely on it. - */ + /// ID of the session this metric is attached to. `nil` until the metric is handed to a session + /// (`Session.receiveMetric`) or hydrated from the database — at every JS-observable read path the + /// field is populated, so consumers can rely on it. public var sessionId: String? = nil init( diff --git a/packages/expo-app-metrics/ios/MetricKitSubscriber.swift b/packages/expo-app-metrics/ios/MetricKitSubscriber.swift index cb97e31f2293bc..18305d8a0f1946 100644 --- a/packages/expo-app-metrics/ios/MetricKitSubscriber.swift +++ b/packages/expo-app-metrics/ios/MetricKitSubscriber.swift @@ -10,11 +10,9 @@ import MetricKit // We could use it as a source for metrics that we can't measure in other ways, e.g. CPU usage. final class MetricKitSubscriber: NSObject, MXMetricManagerSubscriber, Sendable { - /** - Processes payloads that MetricKit retained from previous app launches. Call this after - registering the subscriber with `MXMetricManager.shared.add(_:)` so MetricKit has - acknowledged a subscriber for the current process. - */ + /// Processes payloads that MetricKit retained from previous app launches. Call this after + /// registering the subscriber with `MXMetricManager.shared.add(_:)` so MetricKit has + /// acknowledged a subscriber for the current process. func processPastPayloads() { didReceive(MXMetricManager.shared.pastPayloads) didReceive(MXMetricManager.shared.pastDiagnosticPayloads) @@ -22,16 +20,12 @@ final class MetricKitSubscriber: NSObject, MXMetricManagerSubscriber, Sendable { // MARK: - MXMetricManagerSubscriber - /** - Receives payloads with performance metrics like CPU and memory usage. - Sent periodically (usually every 24 hours), or when your app gets steady usage. - */ + /// Receives payloads with performance metrics like CPU and memory usage. + /// Sent periodically (usually every 24 hours), or when your app gets steady usage. func didReceive(_ payloads: [MXMetricPayload]) {} - /** - Receives payloads with diagnostic data like crash logs, hang reports, and more. - Delivered on the next app launch after the event occurs. - */ + /// Receives payloads with diagnostic data like crash logs, hang reports, and more. + /// Delivered on the next app launch after the event occurs. func didReceive(_ payloads: [MXDiagnosticPayload]) { let crashReports = payloads.flatMap { payload in return (payload.crashDiagnostics ?? []).map { diagnostic in diff --git a/packages/expo-app-metrics/ios/Metrics.swift b/packages/expo-app-metrics/ios/Metrics.swift index 911d861087dd9c..9fb3a6d907cc5e 100644 --- a/packages/expo-app-metrics/ios/Metrics.swift +++ b/packages/expo-app-metrics/ios/Metrics.swift @@ -1,38 +1,28 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Protocol for objects containing metrics of a specific category. - */ +/// Protocol for objects containing metrics of a specific category. public protocol Metrics: Codable, Sendable { - /** - Type requirement for the `MetricKeys` enum. All keys must have a raw value and the enum must be iterable. - */ + /// Type requirement for the `MetricKeys` enum. All keys must have a raw value and the enum must be iterable. typealias MetricKey = RawRepresentable & CaseIterable - /** - Enum with keys (not raw values) of the object's properties being a metric value. - */ + /// Enum with keys (not raw values) of the object's properties being a metric value. associatedtype MetricKeys: MetricKey where MetricKeys.RawValue == String - /** - Category of all metrics contained within the object. - */ + /// Category of all metrics contained within the object. static var category: Metric.Category? { get } - /** - Returns an array of metrics contained within the object. - */ + /// Returns an array of metrics contained within the object. func toValues() -> [Metric] } -public extension Metrics { +extension Metrics { // Metrics don't have to be associated with any category (but they should). - static var category: Metric.Category? { + public static var category: Metric.Category? { return nil } // The default implementation captures metric values from each property specified in the `MetricKeys` enum. - func toValues() -> [Metric] { + public func toValues() -> [Metric] { let mirror = Mirror(reflecting: self) let allCases = Self.MetricKeys.allCases diff --git a/packages/expo-app-metrics/ios/MetricsReceiver.swift b/packages/expo-app-metrics/ios/MetricsReceiver.swift index 6ec994f33027b6..3ed5b4fa6716d4 100644 --- a/packages/expo-app-metrics/ios/MetricsReceiver.swift +++ b/packages/expo-app-metrics/ios/MetricsReceiver.swift @@ -1,21 +1,15 @@ // Copyright 2025-present 650 Industries. All rights reserved. public protocol MetricsReceiver { - /** - Receives a group of metrics. - */ + /// Receives a group of metrics. @AppMetricsActor func receiveMetrics(_ metrics: MetricsType) - /** - Receives a single metric. - */ + /// Receives a single metric. @AppMetricsActor func receiveMetric(_ metric: Metric) - /** - Receives a single log record. - */ + /// Receives a single log record. @AppMetricsActor func receiveLog(_ log: LogRecord) } diff --git a/packages/expo-app-metrics/ios/Network/NetworkPath.swift b/packages/expo-app-metrics/ios/Network/NetworkPath.swift index 94e91c11f6e2d6..dffaecbcaac120 100644 --- a/packages/expo-app-metrics/ios/Network/NetworkPath.swift +++ b/packages/expo-app-metrics/ios/Network/NetworkPath.swift @@ -3,12 +3,10 @@ import Foundation import Network -/** - A `Sendable` snapshot of `NWPath` distilled to the fields we care about. We - don't pass `NWPath` itself across actor boundaries because it isn't - `Sendable`, and a stable typed surface decouples downstream code from the - OS API. - */ +/// A `Sendable` snapshot of `NWPath` distilled to the fields we care about. We +/// don't pass `NWPath` itself across actor boundaries because it isn't +/// `Sendable`, and a stable typed surface decouples downstream code from the +/// OS API. struct NetworkPath: Sendable, Equatable { enum Status: String, Sendable { case satisfied @@ -38,24 +36,18 @@ struct NetworkPath: Sendable, Equatable { let interfaceType: InterfaceType let isExpensive: Bool let isConstrained: Bool - /** - Populated only when `status != .satisfied`. Distinguishes "no usable path" - from "user denied cellular/wifi for this app" from "VPN configured but down." - */ + /// Populated only when `status != .satisfied`. Distinguishes "no usable path" + /// from "user denied cellular/wifi for this app" from "VPN configured but down." let unsatisfiedReason: UnsatisfiedReason? - /** - `CACurrentMediaTime` of the snapshot. Useful for transition timing once the - recorder lands. - */ + /// `CACurrentMediaTime` of the snapshot. Useful for transition timing once the + /// recorder lands. let timestamp: TimeInterval } extension NetworkPath { - /** - Builds a snapshot from an `NWPath`. The current implementation reads the - primary interface type via `usesInterfaceType(_:)` predicates because - `NWPath` doesn't expose a single "preferred type" field. - */ + /// Builds a snapshot from an `NWPath`. The current implementation reads the + /// primary interface type via `usesInterfaceType(_:)` predicates because + /// `NWPath` doesn't expose a single "preferred type" field. static func from(_ path: NWPath, at timestamp: TimeInterval) -> NetworkPath { return NetworkPath( status: Status.from(path.status), @@ -68,8 +60,8 @@ extension NetworkPath { } } -private extension NetworkPath.Status { - static func from(_ status: NWPath.Status) -> Self { +extension NetworkPath.Status { + fileprivate static func from(_ status: NWPath.Status) -> Self { switch status { case .satisfied: return .satisfied @@ -83,8 +75,8 @@ private extension NetworkPath.Status { } } -private extension NetworkPath.InterfaceType { - static func from(_ path: NWPath) -> Self { +extension NetworkPath.InterfaceType { + fileprivate static func from(_ path: NWPath) -> Self { if path.status != .satisfied { return .none } @@ -105,8 +97,8 @@ private extension NetworkPath.InterfaceType { } } -private extension NetworkPath.UnsatisfiedReason { - static func from(_ reason: NWPath.UnsatisfiedReason) -> Self { +extension NetworkPath.UnsatisfiedReason { + fileprivate static func from(_ reason: NWPath.UnsatisfiedReason) -> Self { switch reason { case .notAvailable: return .notAvailable diff --git a/packages/expo-app-metrics/ios/Network/NetworkPathMonitor.swift b/packages/expo-app-metrics/ios/Network/NetworkPathMonitor.swift index f64c64ba1381de..c634f8101613a4 100644 --- a/packages/expo-app-metrics/ios/Network/NetworkPathMonitor.swift +++ b/packages/expo-app-metrics/ios/Network/NetworkPathMonitor.swift @@ -1,21 +1,19 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - A singleton that owns the long-lived `NetworkPathObserver` and caches the - most recent `NetworkPath` snapshot. - - The observer is started eagerly at app launch (see - `AppMetricsAppDelegateSubscriber.appDelegateWillBeginInitialization`) so the - cache is warm by the time `markInteractive` reads it. `NWPathMonitor` is - event-driven and cheap, so there's no benefit to deferring the start. - - Readers can either grab the cached `currentPath` synchronously, or `await - waitForFirstPath()` if they specifically need the first OS-delivered path - (and don't mind suspending for it). The latter is what TTI param collection - uses — the TTI value itself is captured from the synchronously-recorded - `markers.timeToInteractive` timestamp, so awaiting the first path here only - delays the local-storage write, not the metric measurement. - */ +/// A singleton that owns the long-lived `NetworkPathObserver` and caches the +/// most recent `NetworkPath` snapshot. +/// +/// The observer is started eagerly at app launch (see +/// `AppMetricsAppDelegateSubscriber.appDelegateWillBeginInitialization`) so the +/// cache is warm by the time `markInteractive` reads it. `NWPathMonitor` is +/// event-driven and cheap, so there's no benefit to deferring the start. +/// +/// Readers can either grab the cached `currentPath` synchronously, or `await +/// waitForFirstPath()` if they specifically need the first OS-delivered path +/// (and don't mind suspending for it). The latter is what TTI param collection +/// uses — the TTI value itself is captured from the synchronously-recorded +/// `markers.timeToInteractive` timestamp, so awaiting the first path here only +/// delays the local-storage write, not the metric measurement. @AppMetricsActor final class NetworkPathMonitor: NetworkPathObserverDelegate, Sendable { static let shared = NetworkPathMonitor() @@ -23,21 +21,17 @@ final class NetworkPathMonitor: NetworkPathObserverDelegate, Sendable { private var observer: NetworkPathObserver? private(set) var currentPath: NetworkPath? - /** - All resumed at once when the first path is delivered. An array (rather - than a single optional) means concurrent callers don't clobber each - other's continuations — useful if a future metric joins the TTI metric in - awaiting the first path. - */ + /// All resumed at once when the first path is delivered. An array (rather + /// than a single optional) means concurrent callers don't clobber each + /// other's continuations — useful if a future metric joins the TTI metric in + /// awaiting the first path. private var firstPathContinuations: [CheckedContinuation] = [] - /** Internal so tests can construct dedicated instances; production code uses `shared`. */ + /// Internal so tests can construct dedicated instances; production code uses `shared`. init() {} - /** - Idempotent. Constructs the observer on the first call; later calls are - no-ops. The observer runs for the app lifetime. - */ + /// Idempotent. Constructs the observer on the first call; later calls are + /// no-ops. The observer runs for the app lifetime. func start() { if observer != nil { return @@ -45,10 +39,8 @@ final class NetworkPathMonitor: NetworkPathObserverDelegate, Sendable { observer = NetworkPathObserver(delegate: self) } - /** - Suspends until the first path delivery, then returns the latest cached - path. Returns immediately if a path has already been received. - */ + /// Suspends until the first path delivery, then returns the latest cached + /// path. Returns immediately if a path has already been received. func waitForFirstPath() async -> NetworkPath? { if currentPath != nil { return currentPath @@ -57,11 +49,9 @@ final class NetworkPathMonitor: NetworkPathObserverDelegate, Sendable { return currentPath } - /** - Caches `path` and resumes any callers awaiting the first path. Tests on - `AppMetricsActor` can call this directly to avoid the async hop in - `onNetworkPathUpdate(_:)`. - */ + /// Caches `path` and resumes any callers awaiting the first path. Tests on + /// `AppMetricsActor` can call this directly to avoid the async hop in + /// `onNetworkPathUpdate(_:)`. func apply(_ path: NetworkPath) { let wasFirst = currentPath == nil currentPath = path diff --git a/packages/expo-app-metrics/ios/Network/NetworkPathObserver.swift b/packages/expo-app-metrics/ios/Network/NetworkPathObserver.swift index 5f0b1f32966322..66b6dcd83e8ba2 100644 --- a/packages/expo-app-metrics/ios/Network/NetworkPathObserver.swift +++ b/packages/expo-app-metrics/ios/Network/NetworkPathObserver.swift @@ -7,13 +7,11 @@ protocol NetworkPathObserverDelegate: AnyObject, Sendable { func onNetworkPathUpdate(_ path: NetworkPath) } -/** - Owns one long-lived `NWPathMonitor` and converts each delivered `NWPath` - into a `Sendable` `NetworkPath` snapshot before handing it off to the - delegate. The monitor runs for the app lifetime — `NWPathMonitor` is cheap - (event-driven, no polling, no radios woken) so there's no benefit to - starting and stopping it around recording windows. - */ +/// Owns one long-lived `NWPathMonitor` and converts each delivered `NWPath` +/// into a `Sendable` `NetworkPath` snapshot before handing it off to the +/// delegate. The monitor runs for the app lifetime — `NWPathMonitor` is cheap +/// (event-driven, no polling, no radios woken) so there's no benefit to +/// starting and stopping it around recording windows. final class NetworkPathObserver: Sendable { private let monitor = NWPathMonitor() private weak let delegate: NetworkPathObserverDelegate? diff --git a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequest.swift b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequest.swift index d46837f2868729..dfb0d75899020e 100644 --- a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequest.swift +++ b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequest.swift @@ -2,108 +2,96 @@ import Foundation -/** - A `Sendable` snapshot of a single HTTP request observed by `NetworkRequestTaskSwizzling`. - - The shape is intentionally close to `URLSessionTaskTransactionMetrics` so we can plumb individual - timing phases into telemetry later without redesigning the type. Until the metrics pipeline is - wired up, this is what gets handed to `NetworkRequestObserverDelegate` callers. - - The URL is recorded verbatim — including the query string — because callers asked for it. Any - redaction (tokens in query parameters, auth headers, etc.) is the responsibility of whatever - downstream layer converts these snapshots into stored metrics. - */ +/// A `Sendable` snapshot of a single HTTP request observed by `NetworkRequestTaskSwizzling`. +/// +/// The shape is intentionally close to `URLSessionTaskTransactionMetrics` so we can plumb individual +/// timing phases into telemetry later without redesigning the type. Until the metrics pipeline is +/// wired up, this is what gets handed to `NetworkRequestObserverDelegate` callers. +/// +/// The URL is recorded verbatim — including the query string — because callers asked for it. Any +/// redaction (tokens in query parameters, auth headers, etc.) is the responsibility of whatever +/// downstream layer converts these snapshots into stored metrics. public struct NetworkRequest: Sendable, Equatable, Identifiable { - /** Stable identifier for this observation. Generated by the protocol class. */ + /// Stable identifier for this observation. Generated by the protocol class. public let id: UUID - /** Request URL as supplied to `URLSession`. May include query parameters and fragments. */ + /// Request URL as supplied to `URLSession`. May include query parameters and fragments. public let url: URL - /** HTTP method (`GET`, `POST`, …). Defaults to `GET` if `URLRequest.httpMethod` was nil. */ + /// HTTP method (`GET`, `POST`, …). Defaults to `GET` if `URLRequest.httpMethod` was nil. public let method: String - /** Response status code, or `nil` if the request failed before headers were received. */ + /// Response status code, or `nil` if the request failed before headers were received. public let statusCode: Int? - /** - Negotiated wire protocol — `http/1.1`, `h2`, `h3` — as reported by - `URLSessionTaskTransactionMetrics.networkProtocolName`. `nil` for cache hits or when the OS - didn't report one. - */ + /// Negotiated wire protocol — `http/1.1`, `h2`, `h3` — as reported by + /// `URLSessionTaskTransactionMetrics.networkProtocolName`. `nil` for cache hits or when the OS + /// didn't report one. public let networkProtocol: String? - /** Number of bytes sent on the wire for the request (headers + body). */ + /// Number of bytes sent on the wire for the request (headers + body). public let requestBytesSent: Int64? - /** Number of bytes received on the wire for the response (headers + body). */ + /// Number of bytes received on the wire for the response (headers + body). public let responseBytesReceived: Int64? - /** Phase-by-phase timings pulled from the most recent (post-redirect) transaction. */ + /// Phase-by-phase timings pulled from the most recent (post-redirect) transaction. public let timings: Timings - /** - Short human-readable error description if the task completed with an error. We keep this as a - string rather than carrying `NSError` so the type stays `Sendable` and serializable. - */ + /// Short human-readable error description if the task completed with an error. We keep this as a + /// string rather than carrying `NSError` so the type stays `Sendable` and serializable. public let errorDescription: String? - /** - Ordered list of redirect hops that preceded the final response. Empty when the task returned - directly. Each entry describes one hop: `fromUrl` is the URL that returned the redirect, - `statusCode` is the 3xx code it returned, and `toUrl` is where the redirect pointed. For a - complete chain the first entry's `fromUrl` equals the parent event's `url`, and the last - entry's `toUrl` is where the request actually landed. - */ + /// Ordered list of redirect hops that preceded the final response. Empty when the task returned + /// directly. Each entry describes one hop: `fromUrl` is the URL that returned the redirect, + /// `statusCode` is the 3xx code it returned, and `toUrl` is where the redirect pointed. For a + /// complete chain the first entry's `fromUrl` equals the parent event's `url`, and the last + /// entry's `toUrl` is where the request actually landed. public let redirects: [Redirect] public struct Redirect: Sendable, Equatable { - /** The URL that returned the redirect. */ + /// The URL that returned the redirect. public let fromUrl: URL - /** The URL the request was redirected to. */ + /// The URL the request was redirected to. public let toUrl: URL - /** The 3xx status code returned by `fromUrl` that caused this hop. */ + /// The 3xx status code returned by `fromUrl` that caused this hop. public let statusCode: Int } public struct Timings: Sendable, Equatable { - /** When the task was started (`URLSessionTaskTransactionMetrics.fetchStartDate`). */ + /// When the task was started (`URLSessionTaskTransactionMetrics.fetchStartDate`). public let fetchStart: Date? - /** When DNS resolution began. `nil` if the host was resolved from cache or the connection was reused. */ + /// When DNS resolution began. `nil` if the host was resolved from cache or the connection was reused. public let domainLookupStart: Date? public let domainLookupEnd: Date? - /** When the TCP connection began. `nil` if a connection was reused. */ + /// When the TCP connection began. `nil` if a connection was reused. public let connectStart: Date? public let connectEnd: Date? - /** TLS handshake window. `nil` for cleartext or reused connections. */ + /// TLS handshake window. `nil` for cleartext or reused connections. public let secureConnectionStart: Date? public let secureConnectionEnd: Date? - /** When the request line began being sent. */ + /// When the request line began being sent. public let requestStart: Date? public let requestEnd: Date? - /** When the first byte of the response arrived (TTFB). */ + /// When the first byte of the response arrived (TTFB). public let responseStart: Date? public let responseEnd: Date? - /** - Total wall-clock duration of the task. Convenience: callers don't have to subtract - `fetchStart` from `responseEnd` themselves, and we can populate this even when the - individual phases are `nil` (cache hits, errors before headers). - */ + /// Total wall-clock duration of the task. Convenience: callers don't have to subtract + /// `fetchStart` from `responseEnd` themselves, and we can populate this even when the + /// individual phases are `nil` (cache hits, errors before headers). public let totalDuration: TimeInterval } } -/** - Lightweight snapshot emitted when a request begins, before any response or timing data exists. - Shares its `id` with the corresponding completion-time `NetworkRequest`, so JS subscribers can - correlate the two events. - */ +/// Lightweight snapshot emitted when a request begins, before any response or timing data exists. +/// Shares its `id` with the corresponding completion-time `NetworkRequest`, so JS subscribers can +/// correlate the two events. public struct NetworkRequestStarted: Sendable, Equatable, Identifiable { public let id: UUID public let url: URL @@ -112,16 +100,14 @@ public struct NetworkRequestStarted: Sendable, Equatable, Identifiable { } extension NetworkRequest { - /** - Builds a snapshot from the data we have at task completion. The metrics argument may be `nil` - for cache-only responses or in tests; in that case, callers fall back to wall-clock timestamps - on the request/response pair. - - `taskBytesSent` / `taskBytesReceived` are the task's wall-clock byte counters - (`URLSessionTask.countOfBytesSent` / `countOfBytesReceived`). Pass `nil` when no task is - available (tests). They're used as a fallback when `metrics`'s per-transaction counters are - zero — see the body for the cache-hit / Simulator quirks that hit that case. - */ + /// Builds a snapshot from the data we have at task completion. The metrics argument may be `nil` + /// for cache-only responses or in tests; in that case, callers fall back to wall-clock timestamps + /// on the request/response pair. + /// + /// `taskBytesSent` / `taskBytesReceived` are the task's wall-clock byte counters + /// (`URLSessionTask.countOfBytesSent` / `countOfBytesReceived`). Pass `nil` when no task is + /// available (tests). They're used as a fallback when `metrics`'s per-transaction counters are + /// zero — see the body for the cache-hit / Simulator quirks that hit that case. static func from( id: UUID, request: URLRequest, @@ -172,7 +158,8 @@ extension NetworkRequest { }() let responseBytesReceived: Int64? = { if let transaction { - let fromTransaction = transaction.countOfResponseHeaderBytesReceived + transaction.countOfResponseBodyBytesReceived + let fromTransaction = + transaction.countOfResponseHeaderBytesReceived + transaction.countOfResponseBodyBytesReceived if fromTransaction > 0 { return fromTransaction } diff --git a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestMonitor.swift b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestMonitor.swift index ed8b23d221f7db..ef3f166b6672ae 100644 --- a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestMonitor.swift +++ b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestMonitor.swift @@ -2,11 +2,9 @@ import Foundation -/** - Receives notifications about HTTP requests observed by `NetworkRequestTaskSwizzling`. Both - methods have default no-op implementations so delegates can opt into either start- or - complete-time notifications without having to implement the other. - */ +/// Receives notifications about HTTP requests observed by `NetworkRequestTaskSwizzling`. Both +/// methods have default no-op implementations so delegates can opt into either start- or +/// complete-time notifications without having to implement the other. public protocol NetworkRequestObserverDelegate: AnyObject, Sendable { func onNetworkRequestStarted(_ request: NetworkRequestStarted) func onNetworkRequestCompleted(_ request: NetworkRequest) @@ -19,46 +17,42 @@ public protocol NetworkRequestObserverDelegate: AnyObject, Sendable { func shouldObserveRequest(url: URL, method: String) -> Bool } -public extension NetworkRequestObserverDelegate { - func onNetworkRequestStarted(_ request: NetworkRequestStarted) {} - func onNetworkRequestCompleted(_ request: NetworkRequest) {} +extension NetworkRequestObserverDelegate { + public func onNetworkRequestStarted(_ request: NetworkRequestStarted) {} + public func onNetworkRequestCompleted(_ request: NetworkRequest) {} - func shouldObserveRequest(url: URL, method: String) -> Bool { + public func shouldObserveRequest(url: URL, method: String) -> Bool { return true } } -/** - A singleton that aggregates `NetworkRequest` snapshots delivered by the URLSessionTask swizzles. - - The monitor is the central seam between the swizzle layer (which observes individual tasks - complete) and whatever future layer routes those observations into telemetry. For now it keeps a - small in-memory ring buffer of recent requests (useful for debug surfaces and tests) and fans - each completion out to registered delegates. - - Started eagerly at app launch (see `AppMetricsAppDelegateSubscriber.appDelegateWillBeginInitialization`) - so the swizzles run before React Native makes its first fetch. - */ +/// A singleton that aggregates `NetworkRequest` snapshots delivered by the URLSessionTask swizzles. +/// +/// The monitor is the central seam between the swizzle layer (which observes individual tasks +/// complete) and whatever future layer routes those observations into telemetry. For now it keeps a +/// small in-memory ring buffer of recent requests (useful for debug surfaces and tests) and fans +/// each completion out to registered delegates. +/// +/// Started eagerly at app launch (see `AppMetricsAppDelegateSubscriber.appDelegateWillBeginInitialization`) +/// so the swizzles run before React Native makes its first fetch. @AppMetricsActor public final class NetworkRequestMonitor: Sendable { public static let shared = NetworkRequestMonitor() - /** Maximum number of recent requests retained for debug surfaces. */ + /// Maximum number of recent requests retained for debug surfaces. private let recentCapacity = 200 private var recentRequests: [NetworkRequest] = [] private var delegates: [WeakDelegate] = [] private var started = false - /** Internal so tests can construct dedicated instances; production code uses `shared`. */ + /// Internal so tests can construct dedicated instances; production code uses `shared`. init() {} - /** - Confirms the URLSessionTask swizzles are installed. The app-delegate subscriber already - installs them synchronously at launch (before the first request); this re-asserts the install - for any path that reaches the monitor without going through the subscriber. Idempotent — - subsequent calls are no-ops. - */ + /// Confirms the URLSessionTask swizzles are installed. The app-delegate subscriber already + /// installs them synchronously at launch (before the first request); this re-asserts the install + /// for any path that reaches the monitor without going through the subscriber. Idempotent — + /// subsequent calls are no-ops. func start() { if started { return @@ -67,20 +61,16 @@ public final class NetworkRequestMonitor: Sendable { NetworkRequestTaskSwizzling.install() } - /** - Most recently observed requests, oldest first. Bounded by `recentCapacity`. Intended for - debug surfaces; not for the dispatch path. - */ + /// Most recently observed requests, oldest first. Bounded by `recentCapacity`. Intended for + /// debug surfaces; not for the dispatch path. public var recent: [NetworkRequest] { return recentRequests } - /** - Folds the requests whose `timings.fetchStart` falls within `[start, end]` into a summary. - Used by the TTI metric to attach a per-launch network rollup. Bounded by the ring buffer: - under heavy network load the earliest requests in the window may have been evicted, in - which case the summary undercounts — acceptable for a TTI-attached signal. - */ + /// Folds the requests whose `timings.fetchStart` falls within `[start, end]` into a summary. + /// Used by the TTI metric to attach a per-launch network rollup. Bounded by the ring buffer: + /// under heavy network load the earliest requests in the window may have been evicted, in + /// which case the summary undercounts — acceptable for a TTI-attached signal. func summarize(start: Date, end: Date) -> NetworkRequestSummary { let inWindow = recentRequests.filter { request in guard let fetchStart = request.timings.fetchStart else { @@ -91,9 +81,7 @@ public final class NetworkRequestMonitor: Sendable { return NetworkRequestSummary.from(inWindow) } - /** - Adds a delegate that will be notified for each completed request. Delegates are held weakly. - */ + /// Adds a delegate that will be notified for each completed request. Delegates are held weakly. public func addDelegate(_ delegate: NetworkRequestObserverDelegate) { pruneDelegates() delegates.append(WeakDelegate(value: delegate)) @@ -103,11 +91,9 @@ public final class NetworkRequestMonitor: Sendable { delegates.removeAll { $0.value === delegate || $0.value == nil } } - /** - Records a completed request: appends to the ring buffer and fans it out to delegates. Called - from `NetworkRequestTaskSwizzling.recordCompletion` (which fires from either the delegate proxy's - metrics callback or the `setState:` fallback) on the `AppMetricsActor`. - */ + /// Records a completed request: appends to the ring buffer and fans it out to delegates. Called + /// from `NetworkRequestTaskSwizzling.recordCompletion` (which fires from either the delegate proxy's + /// metrics callback or the `setState:` fallback) on the `AppMetricsActor`. func record(_ request: NetworkRequest) { recentRequests.append(request) if recentRequests.count > recentCapacity { @@ -124,11 +110,9 @@ public final class NetworkRequestMonitor: Sendable { } } - /** - Records that a request has begun. No ring-buffer entry — the started snapshot is purely a - notification used to surface in-flight state to subscribers. The corresponding completion - event will arrive later with a matching `id`. - */ + /// Records that a request has begun. No ring-buffer entry — the started snapshot is purely a + /// notification used to surface in-flight state to subscribers. The corresponding completion + /// event will arrive later with a matching `id`. func recordStart(_ request: NetworkRequestStarted) { pruneDelegates() for entry in delegates { diff --git a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestObserver.swift b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestObserver.swift index 1fc1c52378d117..19fed546a1eda1 100644 --- a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestObserver.swift +++ b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestObserver.swift @@ -3,20 +3,20 @@ import ExpoModulesCore import Foundation -/** Event names emitted by `NetworkRequestObserver`, matching the keys in the JS - `NetworkRequestObserverEvents` type. */ +/// Event names emitted by `NetworkRequestObserver`, matching the keys in the JS +/// `NetworkRequestObserverEvents` type. +// swift-format-ignore: AlwaysUseLowerCamelCase let REQUEST_STARTED_EVENT = "requestStarted" +// swift-format-ignore: AlwaysUseLowerCamelCase let REQUEST_COMPLETED_EVENT = "requestCompleted" -/** - JS-facing `SharedObject` that bridges per-instance subscriptions to the singleton - `NetworkRequestMonitor`. Each JS `new NetworkRequestObserver()` allocates one of these and - registers it as a delegate; the native instance is released when JS drops the reference, at - which point `sharedObjectWillRelease` removes the delegate registration. - - The class only forwards events — it doesn't store request history. Use `NetworkRequestMonitor`'s - in-process API for that. - */ +/// JS-facing `SharedObject` that bridges per-instance subscriptions to the singleton +/// `NetworkRequestMonitor`. Each JS `new NetworkRequestObserver()` allocates one of these and +/// registers it as a delegate; the native instance is released when JS drops the reference, at +/// which point `sharedObjectWillRelease` removes the delegate registration. +/// +/// The class only forwards events — it doesn't store request history. Use `NetworkRequestMonitor`'s +/// in-process API for that. public final class NetworkRequestObserver: SharedObject, NetworkRequestObserverDelegate, @unchecked Sendable { /// The active filter, or `nil` to observe every request. Held in a `Mutex` so the read from the /// monitor's fan-out (`shouldObserveRequest`) and the swap from `setFilter` are atomic: a @@ -69,15 +69,15 @@ public final class NetworkRequestObserver: SharedObject, NetworkRequestObserverD return filter.matches(url: url, method: method) } - /** Internal so tests can assert the payload shape without going through `emit`, which needs a - live JS runtime. The keys here are part of the public JS contract — additions are safe but - renames are breaking. */ + /// Internal so tests can assert the payload shape without going through `emit`, which needs a + /// live JS runtime. The keys here are part of the public JS contract — additions are safe but + /// renames are breaking. static func startedPayload(for request: NetworkRequestStarted) -> [String: Any?] { return [ "id": request.id.uuidString, "url": request.url.absoluteString, "method": request.method, - "startedAt": request.startedAt.ISO8601Format() + "startedAt": request.startedAt.ISO8601Format(), ] } @@ -98,9 +98,9 @@ public final class NetworkRequestObserver: SharedObject, NetworkRequestObserverD return [ "fromUrl": $0.fromUrl.absoluteString, "toUrl": $0.toUrl.absoluteString, - "statusCode": $0.statusCode + "statusCode": $0.statusCode, ] - } + }, ] } } diff --git a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestSummary.swift b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestSummary.swift index 99f9423152de3c..e3eccfa4f90514 100644 --- a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestSummary.swift +++ b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestSummary.swift @@ -2,36 +2,34 @@ import Foundation -/** - An aggregate over a set of `NetworkRequest` snapshots. Designed to be flattened into a metric's - `params` map, so all fields are simple value types and the type itself stays `Sendable`. - - The summary is intentionally small. Anything that would explode cardinality (per-URL p95s, full - request lists) belongs in a separate metric/table once we ship one — not on the TTI envelope. - */ +/// An aggregate over a set of `NetworkRequest` snapshots. Designed to be flattened into a metric's +/// `params` map, so all fields are simple value types and the type itself stays `Sendable`. +/// +/// The summary is intentionally small. Anything that would explode cardinality (per-URL p95s, full +/// request lists) belongs in a separate metric/table once we ship one — not on the TTI envelope. public struct NetworkRequestSummary: Sendable, Equatable { - /** Number of requests in the window. */ + /// Number of requests in the window. public let count: Int - /** Requests that errored or returned a non-2xx status. */ + /// Requests that errored or returned a non-2xx status. public let failed: Int - /** Sum of `responseBytesReceived` across all requests in the window. */ + /// Sum of `responseBytesReceived` across all requests in the window. public let bytesReceived: Int64 - /** Sum of `requestBytesSent` across all requests in the window. */ + /// Sum of `requestBytesSent` across all requests in the window. public let bytesSent: Int64 - /** Sum of `timings.totalDuration` across all requests. Can exceed wall-clock when requests overlap. */ + /// Sum of `timings.totalDuration` across all requests. Can exceed wall-clock when requests overlap. public let totalDuration: TimeInterval - /** Longest single request duration in the window, or `nil` if `count == 0`. */ + /// Longest single request duration in the window, or `nil` if `count == 0`. public let slowestDuration: TimeInterval? - /** Host of the slowest request, or `nil` if the request had no resolvable host. */ + /// Host of the slowest request, or `nil` if the request had no resolvable host. public let slowestHost: String? - /** Convenience: returns `nil` when the summary is empty so callers can skip emitting fields. */ + /// Convenience: returns `nil` when the summary is empty so callers can skip emitting fields. public var isEmpty: Bool { return count == 0 } @@ -46,10 +44,8 @@ public struct NetworkRequestSummary: Sendable, Equatable { slowestHost: nil ) - /** - Folds a sequence of `NetworkRequest` into a summary. The caller is responsible for filtering - the sequence to the desired window. - */ + /// Folds a sequence of `NetworkRequest` into a summary. The caller is responsible for filtering + /// the sequence to the desired window. static func from(_ requests: [NetworkRequest]) -> NetworkRequestSummary { if requests.isEmpty { return .empty @@ -89,13 +85,11 @@ public struct NetworkRequestSummary: Sendable, Equatable { } extension NetworkRequest { - /** - A request is treated as failed if it errored, or returned a 4xx (client error) or 5xx (server - error) status. 1xx (informational), 2xx (success), and 3xx (redirection — usually followed - transparently by URLSession, but the unfollowed case is still a successful response from the - origin's perspective) are not failures. A missing status code (the request failed before - headers arrived) counts as failed. - */ + /// A request is treated as failed if it errored, or returned a 4xx (client error) or 5xx (server + /// error) status. 1xx (informational), 2xx (success), and 3xx (redirection — usually followed + /// transparently by URLSession, but the unfollowed case is still a successful response from the + /// origin's perspective) are not failures. A missing status code (the request failed before + /// headers arrived) counts as failed. var isFailed: Bool { if errorDescription != nil { return true diff --git a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestTaskSwizzling.swift b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestTaskSwizzling.swift index 6ab19b5d8cb6ad..c2ff9e5c4d7e89 100644 --- a/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestTaskSwizzling.swift +++ b/packages/expo-app-metrics/ios/NetworkRequests/NetworkRequestTaskSwizzling.swift @@ -1,120 +1,114 @@ // Copyright 2025-present 650 Industries. All rights reserved. +import ExpoModulesCore import Foundation import ObjectiveC -import ExpoModulesCore - -/** - Process-wide observation of every `URLSessionTask` that runs on any `URLSession` the app creates. - - ## Why method swizzling instead of `URLProtocol` - - An earlier draft of this module used a `URLProtocol` subclass plus configuration swizzling. That - has a fundamental flaw: a `URLProtocol` only sees the `URLRequest`, not the originating - `URLSession`. To actually run the request we replayed it through a singleton inner session, - which silently dropped per-session state — cookies, proxy, TLS settings, `httpAdditionalHeaders`, - cache policy — and broke the very isolation guarantees ephemeral sessions are picked for. - - The established observability SDKs (Sentry, Datadog, Bugsnag, New Relic) all converged on method - swizzling at the `URLSessionTask` level. We do the same here. - - ## What we swizzle - - Two methods on `__NSCFLocalSessionTask`, the private concrete class that backs every public - `URLSessionTask` on iOS 12+. The class name has been stable across iOS versions; the same - approach is used in production by Datadog and Bugsnag. - - 1. **`-resume`** — fires once per task at start time. We attach an `ObservationContext` to the - task via `objc_setAssociatedObject` so observation state travels with it across delegate - callbacks and threads, and emit `requestStarted`. - - 2. **`-setState:`** — fires on every state transition. On `.completed` we read `task.error`, - `task.response`, and the task's wall-clock byte counters, build a `NetworkRequest` - snapshot, and emit `requestCompleted`. - - The `setState:` hook is the universal completion seam: it fires for tasks created with a - completion handler (no public delegate path), tasks running on `URLSession.shared` (Apple's - private delegate), and tasks awaited via `async`/`await`. Delegate-based completion handlers - alone would miss all three. - - ## Per-phase metrics via delegate proxy - - `URLSessionTaskMetrics` (redirect chain, DNS/connect/TLS timestamps) is only available through - `urlSession(_:task:didFinishCollecting:)`, which requires a session delegate. We swizzle - `+sessionWithConfiguration:delegate:delegateQueue:` to wrap the caller's delegate in a - `DelegateProxy` that captures metrics into the task's `ObservationContext` while forwarding - every other selector to the caller's original delegate via Objective-C method forwarding. - - Tasks without a delegate (the shared session, completion-handler tasks) still get observed via - the `setState:` hook — they just won't carry per-phase metric detail. - - ## Recursion safety - - expo-observe sets `Expo-AppMetrics-Skip: 1` on outgoing telemetry uploads. The `resume` swizzle - checks for this header on `task.originalRequest` and skips attaching observation state. The - header is forwarded to the server as-is — it lands on o.expo.dev, which we control. - - ## What we don't catch - - - **WebSocket tasks.** `URLSessionWebSocketTask` extends `URLSessionTask` so the swizzles fire, - but websockets don't produce meaningful HTTP metrics. We skip them inside the `resume` hook. - - ## Dev-launcher interop - - When expo-dev-launcher's network inspector is active (`EX_DEV_CLIENT_NETWORK_INSPECTOR` debug - flag), `ExpoRequestInterceptorProtocol` runs every user-facing fetch through a replay on its - own private `URLSession`. The user-facing fetch produces two `__NSCFLocalSessionTask` instances: - - - an **outer** task on the caller's `URLSession`, which fires `resume` first but whose metrics - are degraded (the URLProtocol short-circuits the real network). - - an **inner** task on dev-launcher's `URLSession`, which carries the real - `URLSessionTaskMetrics` (redirect chain, per-phase timings, byte splits). - We pair them up by request URL: the outer's `resume` creates an `ObservationContext` and adds - it to `pendingReplays`; the inner's `resume` (microseconds later) claims it via - `takePendingReplay`, attaches the same context to the inner task, and flags the outer's - setState/metrics paths to short-circuit. Recording happens once, from the inner task's - `didFinishCollectingMetrics:` callback, carrying the inner task's real metrics and the outer's - `requestStarted` event id. See `pendingReplays` for the data structure. - */ +/// Process-wide observation of every `URLSessionTask` that runs on any `URLSession` the app creates. +/// +/// ## Why method swizzling instead of `URLProtocol` +/// +/// An earlier draft of this module used a `URLProtocol` subclass plus configuration swizzling. That +/// has a fundamental flaw: a `URLProtocol` only sees the `URLRequest`, not the originating +/// `URLSession`. To actually run the request we replayed it through a singleton inner session, +/// which silently dropped per-session state — cookies, proxy, TLS settings, `httpAdditionalHeaders`, +/// cache policy — and broke the very isolation guarantees ephemeral sessions are picked for. +/// +/// The established observability SDKs (Sentry, Datadog, Bugsnag, New Relic) all converged on method +/// swizzling at the `URLSessionTask` level. We do the same here. +/// +/// ## What we swizzle +/// +/// Two methods on `__NSCFLocalSessionTask`, the private concrete class that backs every public +/// `URLSessionTask` on iOS 12+. The class name has been stable across iOS versions; the same +/// approach is used in production by Datadog and Bugsnag. +/// +/// 1. **`-resume`** — fires once per task at start time. We attach an `ObservationContext` to the +/// task via `objc_setAssociatedObject` so observation state travels with it across delegate +/// callbacks and threads, and emit `requestStarted`. +/// +/// 2. **`-setState:`** — fires on every state transition. On `.completed` we read `task.error`, +/// `task.response`, and the task's wall-clock byte counters, build a `NetworkRequest` +/// snapshot, and emit `requestCompleted`. +/// +/// The `setState:` hook is the universal completion seam: it fires for tasks created with a +/// completion handler (no public delegate path), tasks running on `URLSession.shared` (Apple's +/// private delegate), and tasks awaited via `async`/`await`. Delegate-based completion handlers +/// alone would miss all three. +/// +/// ## Per-phase metrics via delegate proxy +/// +/// `URLSessionTaskMetrics` (redirect chain, DNS/connect/TLS timestamps) is only available through +/// `urlSession(_:task:didFinishCollecting:)`, which requires a session delegate. We swizzle +/// `+sessionWithConfiguration:delegate:delegateQueue:` to wrap the caller's delegate in a +/// `DelegateProxy` that captures metrics into the task's `ObservationContext` while forwarding +/// every other selector to the caller's original delegate via Objective-C method forwarding. +/// +/// Tasks without a delegate (the shared session, completion-handler tasks) still get observed via +/// the `setState:` hook — they just won't carry per-phase metric detail. +/// +/// ## Recursion safety +/// +/// expo-observe sets `Expo-AppMetrics-Skip: 1` on outgoing telemetry uploads. The `resume` swizzle +/// checks for this header on `task.originalRequest` and skips attaching observation state. The +/// header is forwarded to the server as-is — it lands on o.expo.dev, which we control. +/// +/// ## What we don't catch +/// +/// - **WebSocket tasks.** `URLSessionWebSocketTask` extends `URLSessionTask` so the swizzles fire, +/// but websockets don't produce meaningful HTTP metrics. We skip them inside the `resume` hook. +/// +/// ## Dev-launcher interop +/// +/// When expo-dev-launcher's network inspector is active (`EX_DEV_CLIENT_NETWORK_INSPECTOR` debug +/// flag), `ExpoRequestInterceptorProtocol` runs every user-facing fetch through a replay on its +/// own private `URLSession`. The user-facing fetch produces two `__NSCFLocalSessionTask` instances: +/// +/// - an **outer** task on the caller's `URLSession`, which fires `resume` first but whose metrics +/// are degraded (the URLProtocol short-circuits the real network). +/// - an **inner** task on dev-launcher's `URLSession`, which carries the real +/// `URLSessionTaskMetrics` (redirect chain, per-phase timings, byte splits). +/// +/// We pair them up by request URL: the outer's `resume` creates an `ObservationContext` and adds +/// it to `pendingReplays`; the inner's `resume` (microseconds later) claims it via +/// `takePendingReplay`, attaches the same context to the inner task, and flags the outer's +/// setState/metrics paths to short-circuit. Recording happens once, from the inner task's +/// `didFinishCollectingMetrics:` callback, carrying the inner task's real metrics and the outer's +/// `requestStarted` event id. See `pendingReplays` for the data structure. enum NetworkRequestTaskSwizzling { - /** - Header name any caller can set to opt a request out of observation. Outgoing telemetry uploads - in expo-observe set this so they don't recursively observe themselves. - - The header is forwarded to the destination verbatim — once a `URLSessionTask` is created we - can't safely mutate `originalRequest`, so we read it but don't strip it. The intended use is - on requests to endpoints we control (o.expo.dev); setting it on a request to a third party - leaks `Expo-AppMetrics-Skip: 1` to that host. - - No `X-` prefix per RFC 6648. Callers that can't import this constant (expo-observe must not - depend on app-metrics internals) hardcode the same literal — keep the two in sync if this - ever changes. - */ + /// Header name any caller can set to opt a request out of observation. Outgoing telemetry uploads + /// in expo-observe set this so they don't recursively observe themselves. + /// + /// The header is forwarded to the destination verbatim — once a `URLSessionTask` is created we + /// can't safely mutate `originalRequest`, so we read it but don't strip it. The intended use is + /// on requests to endpoints we control (o.expo.dev); setting it on a request to a third party + /// leaks `Expo-AppMetrics-Skip: 1` to that host. + /// + /// No `X-` prefix per RFC 6648. Callers that can't import this constant (expo-observe must not + /// depend on app-metrics internals) hardcode the same literal — keep the two in sync if this + /// ever changes. static let internalHeaderName = "Expo-AppMetrics-Skip" - /** - Property key that expo-dev-launcher's `ExpoRequestInterceptorProtocol` stamps on the inner - request it creates when replaying a request through its own `URLSession` (dev mode only, gated - on `EX_DEV_CLIENT_NETWORK_INSPECTOR`). - - When the dev-launcher inspector is active, every user-facing fetch produces two tasks: - - an **outer** task created against the user's `URLSession`, with no property — fires `resume` - first but the network never goes through it (the URLProtocol intercepts). - - an **inner** task on dev-launcher's private `URLSession`, carrying this property — does the - actual network work and carries the real `URLSessionTaskMetrics` (redirects, per-phase - timings, byte splits). - - We want one observation per logical fetch, with the inner task's metrics. The resume swizzle - moves the outer's `ObservationContext` to the inner via `pendingReplays` (URL-keyed) so the - inner records into the same id the user-facing `requestStarted` event used. The outer task's - setState/metrics callbacks then short-circuit on `context.replayedByDevLauncher`. - - The literal must match `REQUEST_ID` in - `packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift`. The value - is internal to that file (no public symbol); duplicating the string is the same trick the - expo-observe header constant uses. Keep them in sync. - */ + /// Property key that expo-dev-launcher's `ExpoRequestInterceptorProtocol` stamps on the inner + /// request it creates when replaying a request through its own `URLSession` (dev mode only, gated + /// on `EX_DEV_CLIENT_NETWORK_INSPECTOR`). + /// + /// When the dev-launcher inspector is active, every user-facing fetch produces two tasks: + /// - an **outer** task created against the user's `URLSession`, with no property — fires `resume` + /// first but the network never goes through it (the URLProtocol intercepts). + /// - an **inner** task on dev-launcher's private `URLSession`, carrying this property — does the + /// actual network work and carries the real `URLSessionTaskMetrics` (redirects, per-phase + /// timings, byte splits). + /// + /// We want one observation per logical fetch, with the inner task's metrics. The resume swizzle + /// moves the outer's `ObservationContext` to the inner via `pendingReplays` (URL-keyed) so the + /// inner records into the same id the user-facing `requestStarted` event used. The outer task's + /// setState/metrics callbacks then short-circuit on `context.replayedByDevLauncher`. + /// + /// The literal must match `REQUEST_ID` in + /// `packages/expo-modules-core/ios/DevTools/ExpoRequestInterceptorProtocol.swift`. The value + /// is internal to that file (no public symbol); duplicating the string is the same trick the + /// expo-observe header constant uses. Keep them in sync. fileprivate static let devLauncherRequestIdKey = "ExpoRequestInterceptorProtocol.requestId" /// Installs the swizzles. Idempotent — guarded by `installed` so repeat calls are no-ops. @@ -148,17 +142,15 @@ enum NetworkRequestTaskSwizzling { private static let originalSetStateImp = Mutex(nil) private static let originalSessionInitImp = Mutex(nil) - /** - How long the `setState:` fallback waits before recording. Tasks observed via the delegate - proxy record from `didFinishCollectingMetrics:` first (with metrics) and flip `recorded=true`; - the fallback that fires after this delay sees the flag and skips. Delegate-less sessions - (`URLSession.shared`, completion-handler tasks) never get a metrics callback, so the fallback - wins and records without metrics — degraded but better than nothing. - - 200ms is comfortably above the observed inter-callback latency on real devices (typically a - few ms). The cost is a small latency before the `requestCompleted` event fires for delegate- - less traffic; acceptable for a passive observer. - */ + /// How long the `setState:` fallback waits before recording. Tasks observed via the delegate + /// proxy record from `didFinishCollectingMetrics:` first (with metrics) and flip `recorded=true`; + /// the fallback that fires after this delay sees the flag and skips. Delegate-less sessions + /// (`URLSession.shared`, completion-handler tasks) never get a metrics callback, so the fallback + /// wins and records without metrics — degraded but better than nothing. + /// + /// 200ms is comfortably above the observed inter-callback latency on real devices (typically a + /// few ms). The cost is a small latency before the `requestCompleted` event fires for delegate- + /// less traffic; acceptable for a passive observer. private static let setStateFallbackDelay: TimeInterval = 0.2 /// Outer-task `ObservationContext`s waiting for the corresponding dev-launcher inner replay @@ -330,18 +322,16 @@ enum NetworkRequestTaskSwizzling { // MARK: - setState: swizzle (fallback recording for delegate-less sessions) - /** - `__NSCFLocalSessionTask.setState:` fires on every state transition for every task in the - process. We use it as a fallback recorder for tasks whose session doesn't have our - `DelegateProxy` installed: `URLSession.shared`, sessions created via paths that bypassed our - session-init swizzle, and async/await consumers that go through Apple's internal delegate. - - For delegate-based sessions the `DelegateProxy.urlSession(_:task:didFinishCollecting:)` - callback records first (with metrics) and flips `context.recorded`. This fallback fires later - and short-circuits on the flag. For delegate-less sessions metrics never arrive, the fallback - wins after `setStateFallbackDelay`, and the snapshot lands without per-phase metrics — same - degraded shape as a cache hit or an error before headers. - */ + /// `__NSCFLocalSessionTask.setState:` fires on every state transition for every task in the + /// process. We use it as a fallback recorder for tasks whose session doesn't have our + /// `DelegateProxy` installed: `URLSession.shared`, sessions created via paths that bypassed our + /// session-init swizzle, and async/await consumers that go through Apple's internal delegate. + /// + /// For delegate-based sessions the `DelegateProxy.urlSession(_:task:didFinishCollecting:)` + /// callback records first (with metrics) and flips `context.recorded`. This fallback fires later + /// and short-circuits on the flag. For delegate-less sessions metrics never arrive, the fallback + /// wins after `setStateFallbackDelay`, and the snapshot lands without per-phase metrics — same + /// degraded shape as a cache hit or an error before headers. private static func installSetStateSwizzle() { guard let taskClass = NSClassFromString("__NSCFLocalSessionTask") else { return @@ -386,9 +376,10 @@ enum NetworkRequestTaskSwizzling { // `didFinishCollectingMetrics:` with the real metrics chain. Skip the outer's fallback so we // don't race the inner's recording. The inner task's setState fallback still runs (it has // its own task identity); recordCompletion's `context.recorded` flag dedupes the two paths. - let isInnerReplayTask = task.originalRequest.flatMap { - URLProtocol.property(forKey: devLauncherRequestIdKey, in: $0) - } != nil + let isInnerReplayTask = + task.originalRequest.flatMap { + URLProtocol.property(forKey: devLauncherRequestIdKey, in: $0) + } != nil if context.replayedByDevLauncher && !isInnerReplayTask { return } @@ -457,44 +448,44 @@ enum NetworkRequestTaskSwizzling { // MARK: - Session initializer swizzle (for URLSessionTaskMetrics) - /** - Swizzles `+[URLSession sessionWithConfiguration:delegate:delegateQueue:]` so we can wrap the - caller's delegate in a `DelegateProxy`. The proxy captures `didFinishCollecting` metrics into - the task's `ObservationContext` while forwarding every other selector to the original. - - Sessions created without a delegate (and `URLSession.shared`) skip this path entirely — they - still get observed by `resume`/`setState:`, just without per-phase metrics. - */ + /// Swizzles `+[URLSession sessionWithConfiguration:delegate:delegateQueue:]` so we can wrap the + /// caller's delegate in a `DelegateProxy`. The proxy captures `didFinishCollecting` metrics into + /// the task's `ObservationContext` while forwarding every other selector to the original. + /// + /// Sessions created without a delegate (and `URLSession.shared`) skip this path entirely — they + /// still get observed by `resume`/`setState:`, just without per-phase metrics. private static func installSessionInitSwizzle() { let target: AnyClass = URLSession.self let selector = NSSelectorFromString("sessionWithConfiguration:delegate:delegateQueue:") guard let method = class_getClassMethod(target, selector) else { return } - let block: @convention(block) ( - AnyObject, - URLSessionConfiguration, - URLSessionDelegate?, - OperationQueue? - ) -> URLSession? = { cls, config, delegate, queue in - // Wrap whatever the caller passed (including nil) so we always see the metrics callback. - // Apple's docs say a nil delegate puts the session in "completion handler" mode; in that - // mode the metrics callback never fires anyway, but wrapping nil is still safe — the - // proxy responds only to the two selectors it handles. - let wrapped = DelegateProxy(wrapping: delegate) - guard let imp = originalSessionInitImp.withLock({ $0 }) else { - return nil + let block: + @convention(block) ( + AnyObject, + URLSessionConfiguration, + URLSessionDelegate?, + OperationQueue? + ) -> URLSession? = { cls, config, delegate, queue in + // Wrap whatever the caller passed (including nil) so we always see the metrics callback. + // Apple's docs say a nil delegate puts the session in "completion handler" mode; in that + // mode the metrics callback never fires anyway, but wrapping nil is still safe — the + // proxy responds only to the two selectors it handles. + let wrapped = DelegateProxy(wrapping: delegate) + guard let imp = originalSessionInitImp.withLock({ $0 }) else { + return nil + } + // The delegate slot in the IMP signature is `AnyObject?` rather than `URLSessionDelegate?` + // because `DelegateProxy` deliberately doesn't declare Swift `URLSessionDelegate` conformance + // (see the class doc for why). At the Obj-C ABI level the slot is `id?`, + // which accepts any `NSObject` — `URLSession` only checks selector responses at runtime. + let fn = unsafeBitCast( + imp, + to: (@convention(c) (AnyObject, Selector, URLSessionConfiguration, AnyObject?, OperationQueue?) -> URLSession?) + .self + ) + return fn(cls, selector, config, wrapped, queue) } - // The delegate slot in the IMP signature is `AnyObject?` rather than `URLSessionDelegate?` - // because `DelegateProxy` deliberately doesn't declare Swift `URLSessionDelegate` conformance - // (see the class doc for why). At the Obj-C ABI level the slot is `id?`, - // which accepts any `NSObject` — `URLSession` only checks selector responses at runtime. - let fn = unsafeBitCast( - imp, - to: (@convention(c) (AnyObject, Selector, URLSessionConfiguration, AnyObject?, OperationQueue?) -> URLSession?).self - ) - return fn(cls, selector, config, wrapped, queue) - } let newImp = imp_implementationWithBlock(block as Any) let original = method_setImplementation(method, newImp) originalSessionInitImp.withLock { $0 = original } @@ -503,20 +494,18 @@ enum NetworkRequestTaskSwizzling { // MARK: - ObservationContext -/** - Per-task observation state. Stored on the task via `objc_setAssociatedObject` so it travels with - the task across delegate callbacks, redirects, and threads without us maintaining a separate - task→state map. Released automatically when the task or our slot is cleared. - - `@unchecked Sendable` because we cross isolation boundaries by passing the context to - `AppMetricsActor` from `recordCompletion`. The mutable fields (`recorded`, `metrics`, - `replayedByDevLauncher`, `startNotification`) are written from at most two places each, and - the writes that matter for correctness — flipping `recorded`, updating the pending-replays - dictionary, building the snapshot — all run on `AppMetricsActor`. The early - `replayedByDevLauncher = true` write in `observeStart` happens on the resume thread before - any actor work picks the context up, so there's no read-write race in practice. - */ -fileprivate final class ObservationContext: @unchecked Sendable { +/// Per-task observation state. Stored on the task via `objc_setAssociatedObject` so it travels with +/// the task across delegate callbacks, redirects, and threads without us maintaining a separate +/// task→state map. Released automatically when the task or our slot is cleared. +/// +/// `@unchecked Sendable` because we cross isolation boundaries by passing the context to +/// `AppMetricsActor` from `recordCompletion`. The mutable fields (`recorded`, `metrics`, +/// `replayedByDevLauncher`, `startNotification`) are written from at most two places each, and +/// the writes that matter for correctness — flipping `recorded`, updating the pending-replays +/// dictionary, building the snapshot — all run on `AppMetricsActor`. The early +/// `replayedByDevLauncher = true` write in `observeStart` happens on the resume thread before +/// any actor work picks the context up, so there's no read-write race in practice. +private final class ObservationContext: @unchecked Sendable { let id: UUID let request: URLRequest let startDate: Date @@ -555,22 +544,20 @@ fileprivate final class ObservationContext: @unchecked Sendable { // MARK: - DelegateProxy -/** - `NSObject` subclass that captures `didFinishCollectingMetrics` for our observation context while - transparently forwarding every other selector to the caller's original delegate. - - **Why we don't declare `URLSessionTaskDelegate` conformance in Swift.** `URLSession` introspects - its delegate via `conformsToProtocol:(URLSessionDataDelegate)`, `conformsToProtocol:(URLSessionDownloadDelegate)`, - etc., to decide which optional callbacks it should emit. If we conformed to `URLSessionTaskDelegate` - in Swift, the Obj-C runtime would advertise that conformance for the proxy unconditionally — even - when the wrapped delegate is actually a `URLSessionDataDelegate`. That could change which callbacks - fire and break the caller. We instead reflect the wrapped delegate's `responds(to:)` results, plus - `true` for the metrics selector we intercept. This is the same pattern Bugsnag's - `BSGURLSessionPerformanceProxy` uses. - - The metrics callback is implemented as an `@objc` method so the Obj-C runtime can dispatch it via - `responds(to:)` without us declaring formal protocol conformance. - */ +/// `NSObject` subclass that captures `didFinishCollectingMetrics` for our observation context while +/// transparently forwarding every other selector to the caller's original delegate. +/// +/// **Why we don't declare `URLSessionTaskDelegate` conformance in Swift.** `URLSession` introspects +/// its delegate via `conformsToProtocol:(URLSessionDataDelegate)`, `conformsToProtocol:(URLSessionDownloadDelegate)`, +/// etc., to decide which optional callbacks it should emit. If we conformed to `URLSessionTaskDelegate` +/// in Swift, the Obj-C runtime would advertise that conformance for the proxy unconditionally — even +/// when the wrapped delegate is actually a `URLSessionDataDelegate`. That could change which callbacks +/// fire and break the caller. We instead reflect the wrapped delegate's `responds(to:)` results, plus +/// `true` for the metrics selector we intercept. This is the same pattern Bugsnag's +/// `BSGURLSessionPerformanceProxy` uses. +/// +/// The metrics callback is implemented as an `@objc` method so the Obj-C runtime can dispatch it via +/// `responds(to:)` without us declaring formal protocol conformance. private final class DelegateProxy: NSObject { fileprivate let wrapped: URLSessionDelegate? @@ -598,31 +585,32 @@ private final class DelegateProxy: NSObject { return nil } - /** - Canonical recording site. `didFinishCollectingMetrics:` is Apple's "task is fully done" signal - — by the time it fires, the last byte has been transferred and `task.error` / `task.response` - are stable. We capture metrics, record the snapshot, then forward to the wrapped delegate. - - The explicit `@objc` selector matches Apple's mangling exactly. Without it Swift would emit - `urlSession:task:didFinishCollecting:` (the argument-label form), but `URLSession` dispatches - `URLSession:task:didFinishCollectingMetrics:`. We can't inherit the right name from a protocol - because we deliberately don't conform to `URLSessionTaskDelegate` in Swift (see class comment). - - This mirrors Bugsnag's `BSGURLSessionPerformanceDelegate` approach. Sentry takes a different - path (record from `setState:` without metrics) and explicitly trades away redirect-chain - detail; we keep the chain by recording here. - */ + /// Canonical recording site. `didFinishCollectingMetrics:` is Apple's "task is fully done" signal + /// — by the time it fires, the last byte has been transferred and `task.error` / `task.response` + /// are stable. We capture metrics, record the snapshot, then forward to the wrapped delegate. + /// + /// The explicit `@objc` selector matches Apple's mangling exactly. Without it Swift would emit + /// `urlSession:task:didFinishCollecting:` (the argument-label form), but `URLSession` dispatches + /// `URLSession:task:didFinishCollectingMetrics:`. We can't inherit the right name from a protocol + /// because we deliberately don't conform to `URLSessionTaskDelegate` in Swift (see class comment). + /// + /// This mirrors Bugsnag's `BSGURLSessionPerformanceDelegate` approach. Sentry takes a different + /// path (record from `setState:` without metrics) and explicitly trades away redirect-chain + /// detail; we keep the chain by recording here. @objc(URLSession:task:didFinishCollectingMetrics:) func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { - if let context = objc_getAssociatedObject(task, &NetworkRequestTaskSwizzling.observationContextKey) as? ObservationContext { + if let context = objc_getAssociatedObject(task, &NetworkRequestTaskSwizzling.observationContextKey) + as? ObservationContext + { // The outer task under dev-launcher gets a degraded metrics callback (the URLProtocol // short-circuits the real network). The inner replay task's callback is where the real // chain lands. Skip the outer's metrics callback when its context was claimed by an inner // task; the inner's own callback will record. The two tasks are told apart by the // property dev-launcher stamps on the inner's request. - let isInnerReplayTask = task.originalRequest.flatMap { - URLProtocol.property(forKey: NetworkRequestTaskSwizzling.devLauncherRequestIdKey, in: $0) - } != nil + let isInnerReplayTask = + task.originalRequest.flatMap { + URLProtocol.property(forKey: NetworkRequestTaskSwizzling.devLauncherRequestIdKey, in: $0) + } != nil let skipDueToReplay = context.replayedByDevLauncher && !isInnerReplayTask if !skipDueToReplay { context.metrics = metrics diff --git a/packages/expo-app-metrics/ios/Sessions/ForegroundSession.swift b/packages/expo-app-metrics/ios/Sessions/ForegroundSession.swift index 4e99f9e9011010..7ccdbe2b565e88 100644 --- a/packages/expo-app-metrics/ios/Sessions/ForegroundSession.swift +++ b/packages/expo-app-metrics/ios/Sessions/ForegroundSession.swift @@ -1,9 +1,7 @@ -/** - A session that tracks the duration when the app is in the foreground and actively visible to the user. - - A new foreground session starts when the AppDelegate's `applicationDidBecomeActive` is called and - ends when `applicationDidEnterBackground` is called. Each app foregrounding creates a new session. - */ +/// A session that tracks the duration when the app is in the foreground and actively visible to the user. +/// +/// A new foreground session starts when the AppDelegate's `applicationDidBecomeActive` is called and +/// ends when `applicationDidEnterBackground` is called. Each app foregrounding creates a new session. internal final class ForegroundSession: Session, @unchecked Sendable { init() { super.init(type: .foreground) diff --git a/packages/expo-app-metrics/ios/Sessions/JsMetric.swift b/packages/expo-app-metrics/ios/Sessions/JsMetric.swift index c3a12b9511a3b6..d32f45ce49899d 100644 --- a/packages/expo-app-metrics/ios/Sessions/JsMetric.swift +++ b/packages/expo-app-metrics/ios/Sessions/JsMetric.swift @@ -2,9 +2,7 @@ import ExpoModulesCore -/** - JS-facing shape of a metric attached to a session. - */ +/// JS-facing shape of a metric attached to a session. struct JsMetric: Record { @Field var sessionId: String = "" @Field var category: String = "" @@ -29,9 +27,7 @@ struct JsMetric: Record { } } -/** - Mirrors the TypeScript `MetricInput` type (`Metric` minus `sessionId`) - */ +/// Mirrors the TypeScript `MetricInput` type (`Metric` minus `sessionId`) struct SessionMetricInput: Record { @Field var category: String = "" @Field var name: String = "" diff --git a/packages/expo-app-metrics/ios/Sessions/MainSession.swift b/packages/expo-app-metrics/ios/Sessions/MainSession.swift index 221d7dcae1eead..1be77e8d51622b 100644 --- a/packages/expo-app-metrics/ios/Sessions/MainSession.swift +++ b/packages/expo-app-metrics/ios/Sessions/MainSession.swift @@ -2,10 +2,8 @@ import Foundation -/** - Main session starts from launching the app to its termination. Some metrics like the app startup can only be tracked once and globally. - In the future this class will also hold subsessions such as for time spent on a specific screen/route or user-initiated sessions. - */ +/// Main session starts from launching the app to its termination. Some metrics like the app startup can only be tracked once and globally. +/// In the future this class will also hold subsessions such as for time spent on a specific screen/route or user-initiated sessions. public final class MainSession: Session, @unchecked Sendable { let appStartupMonitor = AppStartupMonitoring() let updatesMonitor = UpdatesMonitoring() @@ -27,20 +25,16 @@ public final class MainSession: Session, @unchecked Sendable { } } - /** - Test-only initializer that builds a session with explicit values and skips registering it - with the global storage. Do not use from production code. - */ + /// Test-only initializer that builds a session with explicit values and skips registering it + /// with the global storage. Do not use from production code. init(id: String, startDate: Date, endDate: Date?) { super.init(id: id, type: .main, startDate: startDate, endDate: endDate) } // MARK: - Crash reports - /** - Persists a crash report attributed to this session. Replaces any previously stored report for - this session id (only one crash per session is meaningful). - */ + /// Persists a crash report attributed to this session. Replaces any previously stored report for + /// this session id (only one crash per session is meaningful). @AppMetricsActor func storeCrashReport(_ crashReport: CrashReport) { logger.warn("[AppMetrics] Received crash report:\n\(crashReport)") diff --git a/packages/expo-app-metrics/ios/Sessions/Session.swift b/packages/expo-app-metrics/ios/Sessions/Session.swift index 2df8db8abb3753..338eded642d59b 100644 --- a/packages/expo-app-metrics/ios/Sessions/Session.swift +++ b/packages/expo-app-metrics/ios/Sessions/Session.swift @@ -1,28 +1,18 @@ -import Foundation import ExpoModulesCore +import Foundation -/** - Session is a time frame during the app's lifetime that tracks various metrics from its start till its end. - */ +/// Session is a time frame during the app's lifetime that tracks various metrics from its start till its end. public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { - /** - Unique ID of the session in UUID v4 format. - */ + /// Unique ID of the session in UUID v4 format. public let id: String - /** - Type of the session. It is one of: `main`, `foreground`, `screen`, `custom` or `unknown`. - */ + /// Type of the session. It is one of: `main`, `foreground`, `screen`, `custom` or `unknown`. public let type: SessionType - /** - Date on which the session was created and started. - */ + /// Date on which the session was created and started. public let startDate: Date - /** - Date on which the `stop()` function was called to end the session, or `nil` if the session is still active. - */ + /// Date on which the `stop()` function was called to end the session, or `nil` if the session is still active. private(set) var endDate: Date? init(type: SessionType = .custom) { @@ -48,11 +38,9 @@ public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { } } - /** - Non-registering initializer that builds a session with explicit values. - The caller is responsible for adding it to storage (or skipping that step, - e.g. in tests). - */ + /// Non-registering initializer that builds a session with explicit values. + /// The caller is responsible for adding it to storage (or skipping that step, + /// e.g. in tests). init(id: String, type: SessionType, startDate: Date, endDate: Date?) { self.id = id self.type = type @@ -61,24 +49,18 @@ public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { super.init() } - /** - Whether the session is still running, i.e. did not end yet. - */ + /// Whether the session is still running, i.e. did not end yet. var isActive: Bool { return endDate == nil } - /** - Session's duration in seconds since its start to an end, or until now if the session is still active. - */ + /// Session's duration in seconds since its start to an end, or until now if the session is still active. var duration: TimeInterval { let endDate = self.endDate ?? Date.now return endDate.timeIntervalSince(startDate) } - /** - Stops the session, persists its end timestamp, and writes a final duration metric. - */ + /// Stops the session, persists its end timestamp, and writes a final duration metric. func stop() { if endDate != nil { // Can't stop session more than once @@ -127,27 +109,21 @@ public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { // MARK: - Reading and recording session data - /** - Metrics recorded against this session, decoded from storage. - */ + /// Metrics recorded against this session, decoded from storage. @AppMetricsActor func getMetrics() throws -> [Metric] { let rows = try AppMetrics.database?.getMetrics(sessionId: id) ?? [] return decodeMetrics(from: rows) } - /** - Log records recorded against this session, decoded from storage. - */ + /// Log records recorded against this session, decoded from storage. @AppMetricsActor func getLogs() throws -> [LogRecord] { let rows = try AppMetrics.database?.getLogs(sessionId: id) ?? [] return decodeLogs(from: rows) } - /** - Records a metric against this session. JS-facing: errors propagate so the caller's promise rejects. - */ + /// Records a metric against this session. JS-facing: errors propagate so the caller's promise rejects. @AppMetricsActor func addMetric(_ input: SessionMetricInput) throws { try insert(input.toMetric(sessionId: id)) @@ -167,7 +143,9 @@ public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { do { try insert(metric) } catch { - logger.warn("[AppMetrics] Failed to insert metric \"\(metric.getMetricKey())\" for session \(self.id): \(error.localizedDescription)") + logger.warn( + "[AppMetrics] Failed to insert metric \"\(metric.getMetricKey())\" for session \(self.id): \(error.localizedDescription)" + ) } } @@ -176,7 +154,8 @@ public class Session: SharedObject, MetricsReceiver, @unchecked Sendable { do { try AppMetrics.database?.insert(log: LogRow.from(log: log, sessionId: self.id)) } catch { - logger.warn("[AppMetrics] Failed to insert log \"\(log.name)\" for session \(self.id): \(error.localizedDescription)") + logger.warn( + "[AppMetrics] Failed to insert log \"\(log.name)\" for session \(self.id): \(error.localizedDescription)") } } } diff --git a/packages/expo-app-metrics/ios/Storage/AppInfo.swift b/packages/expo-app-metrics/ios/Storage/AppInfo.swift index 5c61484313e404..9be859b3f3dd53 100644 --- a/packages/expo-app-metrics/ios/Storage/AppInfo.swift +++ b/packages/expo-app-metrics/ios/Storage/AppInfo.swift @@ -2,9 +2,7 @@ import EXUpdatesInterface -/** - Provides some basic informations about the app. - */ +/// Provides some basic informations about the app. public struct AppInfo: Codable, Equatable, Sendable { public let appId: String? public let appName: String? @@ -21,16 +19,12 @@ public struct AppInfo: Codable, Equatable, Sendable { public let runtimeVersion: String? public let requestHeaders: [String: String]? public var channel: String? { - get { - return requestHeaders?["expo-channel-name"] - } + return requestHeaders?["expo-channel-name"] } - /** - True when none of the carried fields are populated. Lets callers omit the whole struct from - wire payloads instead of sending `{ updateId: null, runtimeVersion: null, requestHeaders: null }`, - matching the pre-SQLite shape where `AppInfo.updatesInfo` was itself optional. - */ + /// True when none of the carried fields are populated. Lets callers omit the whole struct from + /// wire payloads instead of sending `{ updateId: null, runtimeVersion: null, requestHeaders: null }`, + /// matching the pre-SQLite shape where `AppInfo.updatesInfo` was itself optional. public var isEmpty: Bool { return updateId == nil && runtimeVersion == nil && requestHeaders == nil } diff --git a/packages/expo-app-metrics/ios/Storage/DeviceInfo.swift b/packages/expo-app-metrics/ios/Storage/DeviceInfo.swift index 68bd100da38906..789cd3d89bef42 100644 --- a/packages/expo-app-metrics/ios/Storage/DeviceInfo.swift +++ b/packages/expo-app-metrics/ios/Storage/DeviceInfo.swift @@ -1,9 +1,7 @@ import SystemConfiguration import UIKit -/** - Provides some basic informations about the device. - */ +/// Provides some basic informations about the device. public struct DeviceInfo: Codable, Equatable, Sendable { public let modelName: String public let modelIdentifier: String @@ -35,9 +33,7 @@ public struct DeviceInfo: Codable, Equatable, Sendable { } } -/** - Returns a device model name, e.g. "iPhone", "iPad" or "iPhone (Simulator)" when the app is running on the simulator. - */ +/// Returns a device model name, e.g. "iPhone", "iPad" or "iPhone (Simulator)" when the app is running on the simulator. @MainActor private func getDeviceModelName(device: UIDevice) -> String { #if targetEnvironment(simulator) @@ -47,9 +43,7 @@ private func getDeviceModelName(device: UIDevice) -> String { #endif } -/** - Returns an identifier of the device model, e.g. "iPhone18,2". - */ +/// Returns an identifier of the device model, e.g. "iPhone18,2". private func getDeviceModelIdentifier() -> String? { #if targetEnvironment(simulator) return ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] diff --git a/packages/expo-app-metrics/ios/Storage/StoredSession.swift b/packages/expo-app-metrics/ios/Storage/StoredSession.swift index bd96c5d4941718..0340cbbfe3f104 100644 --- a/packages/expo-app-metrics/ios/Storage/StoredSession.swift +++ b/packages/expo-app-metrics/ios/Storage/StoredSession.swift @@ -2,12 +2,10 @@ import Foundation -/** - Public, JSON-friendly snapshot of a persisted session. Built from a `SessionWithChildren` row - batch and composed from the same domain types (`AppInfo`, `DeviceInfo`, `Metric`, `LogRecord`, - `CrashReport`) that the rest of the module already exposes — so consumers see one consistent - vocabulary instead of separate row and domain shapes. - */ +/// Public, JSON-friendly snapshot of a persisted session. Built from a `SessionWithChildren` row +/// batch and composed from the same domain types (`AppInfo`, `DeviceInfo`, `Metric`, `LogRecord`, +/// `CrashReport`) that the rest of the module already exposes — so consumers see one consistent +/// vocabulary instead of separate row and domain shapes. public struct StoredSession: Codable, Sendable { public let id: String public let type: Session.SessionType @@ -21,12 +19,10 @@ public struct StoredSession: Codable, Sendable { public let logs: [LogRecord] public let crashReport: CrashReport? - /** - Projects a row + child batch from the database into the public `StoredSession` shape. JSON-encoded - blobs (request headers, metric params, log attributes, crash report payload) are decoded back into - their typed counterparts; rows with malformed blobs degrade gracefully (the offending field becomes - nil) rather than failing the whole conversion. - */ + /// Projects a row + child batch from the database into the public `StoredSession` shape. JSON-encoded + /// blobs (request headers, metric params, log attributes, crash report payload) are decoded back into + /// their typed counterparts; rows with malformed blobs degrade gracefully (the offending field becomes + /// nil) rather than failing the whole conversion. init(from row: SessionWithChildren) { let session = row.session self.id = session.id @@ -62,11 +58,9 @@ public struct StoredSession: Codable, Sendable { } } -/** - Projects metric rows into the public `Metric` domain shape, decoding the JSON-encoded `params` - blob back into a dictionary. Shared by `StoredSession` and the `Session`/`DebugSession` shared - objects' lazy `getMetrics()` readers. - */ +/// Projects metric rows into the public `Metric` domain shape, decoding the JSON-encoded `params` +/// blob back into a dictionary. Shared by `StoredSession` and the `Session`/`DebugSession` shared +/// objects' lazy `getMetrics()` readers. func decodeMetrics(from rows: [MetricRow]) -> [Metric] { return rows.map { metric in return Metric( @@ -82,11 +76,9 @@ func decodeMetrics(from rows: [MetricRow]) -> [Metric] { } } -/** - Projects log rows into the public `LogRecord` domain shape, decoding the JSON-encoded `attributes` - blob back into a dictionary. Shared by `StoredSession` and the `Session`/`DebugSession` shared - objects' lazy `getLogs()` readers. - */ +/// Projects log rows into the public `LogRecord` domain shape, decoding the JSON-encoded `attributes` +/// blob back into a dictionary. Shared by `StoredSession` and the `Session`/`DebugSession` shared +/// objects' lazy `getLogs()` readers. func decodeLogs(from rows: [LogRow]) -> [LogRecord] { return rows.map { log in return LogRecord( diff --git a/packages/expo-app-metrics/ios/Tests/AppStartupMonitoringTests.swift b/packages/expo-app-metrics/ios/Tests/AppStartupMonitoringTests.swift index 9632add4a7880b..5fc914a30142b4 100644 --- a/packages/expo-app-metrics/ios/Tests/AppStartupMonitoringTests.swift +++ b/packages/expo-app-metrics/ios/Tests/AppStartupMonitoringTests.swift @@ -28,14 +28,15 @@ struct AppStartupMonitoringTests { monitoring.addReceiver(receiver) // Seed `NetworkPathMonitor.shared` so `markInteractive` doesn't suspend // forever waiting for the OS to deliver a real path in the test process. - NetworkPathMonitor.shared.onNetworkPathUpdate(NetworkPath( - status: .satisfied, - interfaceType: .wifi, - isExpensive: false, - isConstrained: false, - unsatisfiedReason: nil, - timestamp: 0 - )) + NetworkPathMonitor.shared.onNetworkPathUpdate( + NetworkPath( + status: .satisfied, + interfaceType: .wifi, + isExpensive: false, + isConstrained: false, + unsatisfiedReason: nil, + timestamp: 0 + )) return monitoring } @@ -110,7 +111,7 @@ struct AppStartupMonitoringTests { monitoring.markInteractive(params: [ "expo.frameRate.slowFrames": 999, - "expo.device.lowPowerMode": "user-supplied" + "expo.device.lowPowerMode": "user-supplied", ]) let metric = try await ttiMetric(from: receiver) diff --git a/packages/expo-app-metrics/ios/Tests/AttributeValidationTests.swift b/packages/expo-app-metrics/ios/Tests/AttributeValidationTests.swift index 21c82990fbab0f..4113582ecce457 100644 --- a/packages/expo-app-metrics/ios/Tests/AttributeValidationTests.swift +++ b/packages/expo-app-metrics/ios/Tests/AttributeValidationTests.swift @@ -35,7 +35,7 @@ struct AttributeValidationTests { let result = sanitizeLogEventAttributes([ "": "x", " ": "y", - "valid": "z" + "valid": "z", ]) #expect(result.droppedCount == 2) let attributes = try! #require(result.attributes) @@ -48,7 +48,7 @@ struct AttributeValidationTests { let result = sanitizeLogEventAttributes([ "expo.app.name": "spoofed", "expo.eas_client.id": "spoofed", - "userId": "u_42" + "userId": "u_42", ]) #expect(result.droppedCount == 2) let attributes = try! #require(result.attributes) @@ -61,7 +61,7 @@ struct AttributeValidationTests { let result = sanitizeLogEventAttributes([ "event.name": "spoofed", "session.id": "spoofed", - "ok": true + "ok": true, ]) #expect(result.droppedCount == 2) let attributes = try! #require(result.attributes) @@ -89,7 +89,7 @@ struct AttributeValidationTests { "expoFoo": "ok", "expo": "ok", "session.idx": "ok", - "event.name.extra": "ok" + "event.name.extra": "ok", ]) #expect(result.droppedCount == 0) let attributes = try! #require(result.attributes) @@ -117,7 +117,7 @@ struct AttributeValidationTests { func `returns nil attributes when every entry is dropped`() { let result = sanitizeLogEventAttributes([ "expo.foo": "x", - "expo.bar": "y" + "expo.bar": "y", ]) #expect(result.attributes == nil) #expect(result.droppedCount == 2) @@ -129,7 +129,7 @@ struct AttributeValidationTests { "": "empty-key-drop", "expo.foo": "namespace-drop", "session.id": "sdk-drop", - "valid": "ok" + "valid": "ok", ]) #expect(result.droppedCount == 3) let attributes = try! #require(result.attributes) diff --git a/packages/expo-app-metrics/ios/Tests/GlobalAttributesTests.swift b/packages/expo-app-metrics/ios/Tests/GlobalAttributesTests.swift index 434866efd23757..a6a292834dc298 100644 --- a/packages/expo-app-metrics/ios/Tests/GlobalAttributesTests.swift +++ b/packages/expo-app-metrics/ios/Tests/GlobalAttributesTests.swift @@ -88,7 +88,7 @@ struct GlobalAttributesTests { GlobalAttributes.set([ "expo.app.name": "spoofed", "session.id": "spoofed", - "tier": "pro" + "tier": "pro", ]) let merged = GlobalAttributes.merged(with: nil) let attributes = try! #require(merged) diff --git a/packages/expo-app-metrics/ios/Tests/MetricsDatabaseTests.swift b/packages/expo-app-metrics/ios/Tests/MetricsDatabaseTests.swift index c382e4ea8876e4..1a53eca4241b37 100644 --- a/packages/expo-app-metrics/ios/Tests/MetricsDatabaseTests.swift +++ b/packages/expo-app-metrics/ios/Tests/MetricsDatabaseTests.swift @@ -315,7 +315,7 @@ struct MetricsDatabaseTests { try database.insertAll(metrics: [ makeMetricRow(sessionId: "s", name: "a"), makeMetricRow(sessionId: "s", name: "b"), - makeMetricRow(sessionId: "s", name: "c") + makeMetricRow(sessionId: "s", name: "c"), ]) let rows = try database.getMetrics(sessionId: "s") @@ -337,16 +337,17 @@ struct MetricsDatabaseTests { func `getMetrics returns rows in insertion order with full payload`() throws { try withTemporaryDatabase { database in try database.insert(session: makeSessionRow(id: "s")) - try database.insert(metric: makeMetricRow( - sessionId: "s", - timestamp: "2026-05-07T12:00:00Z", - category: "frameRate", - name: "slowFrames", - value: 1.5, - routeName: "/home", - updateId: "update-1", - params: "{\"k\":1}" - )) + try database.insert( + metric: makeMetricRow( + sessionId: "s", + timestamp: "2026-05-07T12:00:00Z", + category: "frameRate", + name: "slowFrames", + value: 1.5, + routeName: "/home", + updateId: "update-1", + params: "{\"k\":1}" + )) let row = try #require(try database.getMetrics(sessionId: "s").first) #expect(row.id != nil) @@ -370,7 +371,7 @@ struct MetricsDatabaseTests { try database.insertAll(metrics: [ makeMetricRow(sessionId: "real", name: "first"), makeMetricRow(sessionId: "missing-session", name: "orphan"), - makeMetricRow(sessionId: "real", name: "third") + makeMetricRow(sessionId: "real", name: "third"), ]) } @@ -411,7 +412,7 @@ struct MetricsDatabaseTests { try database.insert(session: makeSessionRow(id: "s")) try database.insertAll(logs: [ makeLogRow(sessionId: "s", name: "a"), - makeLogRow(sessionId: "s", name: "b") + makeLogRow(sessionId: "s", name: "b"), ]) let rows = try database.getLogs(sessionId: "s") @@ -423,15 +424,16 @@ struct MetricsDatabaseTests { func `getLogs returns rows with full payload`() throws { try withTemporaryDatabase { database in try database.insert(session: makeSessionRow(id: "s")) - try database.insert(log: makeLogRow( - sessionId: "s", - timestamp: "2026-05-07T12:00:00Z", - severity: "error", - name: "boom", - body: "something exploded", - attributes: "{\"key\":\"value\"}", - droppedAttributesCount: 3 - )) + try database.insert( + log: makeLogRow( + sessionId: "s", + timestamp: "2026-05-07T12:00:00Z", + severity: "error", + name: "boom", + body: "something exploded", + attributes: "{\"key\":\"value\"}", + droppedAttributesCount: 3 + )) let row = try #require(try database.getLogs(sessionId: "s").first) #expect(row.id != nil) @@ -454,7 +456,7 @@ struct MetricsDatabaseTests { try database.insertAll(logs: [ makeLogRow(sessionId: "real", name: "first"), makeLogRow(sessionId: "missing-session", name: "orphan"), - makeLogRow(sessionId: "real", name: "third") + makeLogRow(sessionId: "real", name: "third"), ]) } @@ -563,11 +565,9 @@ struct MetricsDatabaseTests { // MARK: - Test fixtures and temporary-directory helpers -/** - Runs `body` against a fresh `MetricsDatabase` backed by a unique temporary directory that is - removed once the closure returns. Keeps tests isolated and prevents the user's documents directory - from accumulating leftover `.db` files across test runs. - */ +/// Runs `body` against a fresh `MetricsDatabase` backed by a unique temporary directory that is +/// removed once the closure returns. Keeps tests isolated and prevents the user's documents directory +/// from accumulating leftover `.db` files across test runs. @AppMetricsActor private func withTemporaryDatabase(_ body: (MetricsDatabase) throws -> Void) throws { try withTemporaryDirectory { directoryUrl in diff --git a/packages/expo-app-metrics/ios/Tests/NetworkRequestTests.swift b/packages/expo-app-metrics/ios/Tests/NetworkRequestTests.swift index 6ff06b2c6e172c..775d34cb7097d9 100644 --- a/packages/expo-app-metrics/ios/Tests/NetworkRequestTests.swift +++ b/packages/expo-app-metrics/ios/Tests/NetworkRequestTests.swift @@ -79,7 +79,8 @@ struct NetworkRequestMonitorTests { let snapshot = NetworkRequest.from( id: UUID(), request: URLRequest(url: URL(string: "https://expo.dev/x")!), - response: HTTPURLResponse(url: URL(string: "https://expo.dev/x")!, statusCode: 200, httpVersion: nil, headerFields: nil), + response: HTTPURLResponse( + url: URL(string: "https://expo.dev/x")!, statusCode: 200, httpVersion: nil, headerFields: nil), taskBytesSent: nil, taskBytesReceived: nil, metrics: nil, @@ -322,10 +323,14 @@ struct NetworkRequestSummaryTests { // 304 is a successful conditional-GET cache hit; 301/302 are redirections URLSession // typically follows but if one surfaces here it's still a successful response from the // origin's perspective. Only 4xx/5xx (and explicit errors) belong in the failed count. - let cacheHit = makeRequest(host: "expo.dev", duration: 0.05, status: 304, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) - let redirect = makeRequest(host: "expo.dev", duration: 0.1, status: 301, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) - let clientError = makeRequest(host: "expo.dev", duration: 0.1, status: 404, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) - let serverError = makeRequest(host: "expo.dev", duration: 0.1, status: 500, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) + let cacheHit = makeRequest( + host: "expo.dev", duration: 0.05, status: 304, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) + let redirect = makeRequest( + host: "expo.dev", duration: 0.1, status: 301, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) + let clientError = makeRequest( + host: "expo.dev", duration: 0.1, status: 404, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) + let serverError = makeRequest( + host: "expo.dev", duration: 0.1, status: 500, bytesSent: 0, bytesReceived: 0, fetchStart: Date()) let summary = NetworkRequestSummary.from([cacheHit, redirect, clientError, serverError]) #expect(summary.count == 4) @@ -418,16 +423,14 @@ struct NetworkRequestMonitorWindowingTests { } } -/** - End-to-end tests for `NetworkRequestTaskSwizzling`. We register a `FakeServerProtocol` inside the - test's URLSession so requests never escape the process; the swizzles still fire on the real - `__NSCFLocalSessionTask` Apple creates to drive the URLProtocol, so we observe the full lifecycle - just as we would in production. - - Serialized because every test installs the same process-wide swizzles and shares the monitor's - ring buffer — concurrent runs would observe each other's traffic and the assertions filter by URL - to keep tests independent. - */ +/// End-to-end tests for `NetworkRequestTaskSwizzling`. We register a `FakeServerProtocol` inside the +/// test's URLSession so requests never escape the process; the swizzles still fire on the real +/// `__NSCFLocalSessionTask` Apple creates to drive the URLProtocol, so we observe the full lifecycle +/// just as we would in production. +/// +/// Serialized because every test installs the same process-wide swizzles and shares the monitor's +/// ring buffer — concurrent runs would observe each other's traffic and the assertions filter by URL +/// to keep tests independent. @Suite("NetworkRequestTaskSwizzling", .serialized) struct NetworkRequestTaskSwizzlingTests { init() { @@ -479,11 +482,9 @@ struct NetworkRequestTaskSwizzlingTests { #expect(recorded == nil) } - /** - With task-resume swizzling the caller's session is never replaced — POST bodies reach the - server through the URL loading system's normal path. The fake echoes whatever it receives; a - matching echo proves the body wasn't dropped. - */ + /// With task-resume swizzling the caller's session is never replaced — POST bodies reach the + /// server through the URL loading system's normal path. The fake echoes whatever it receives; a + /// matching echo proves the body wasn't dropped. @Test func `preserves request bodies for uploads`() async throws { let config = URLSessionConfiguration.ephemeral @@ -502,13 +503,11 @@ struct NetworkRequestTaskSwizzlingTests { #expect(data == payload) } - /** - With the swizzle approach the caller's `URLSession` configuration is preserved verbatim — no - inner session, no replay. Ephemeral sessions used to leak cookies into `HTTPCookieStorage.shared` - under the old URLProtocol-replay implementation; this test pins that the leak is gone. - `FakeServerProtocol` returns a `Set-Cookie` header for `/cookie-test`, so the assertion would - fail loudly if cookies started flowing into the shared jar again. - */ + /// With the swizzle approach the caller's `URLSession` configuration is preserved verbatim — no + /// inner session, no replay. Ephemeral sessions used to leak cookies into `HTTPCookieStorage.shared` + /// under the old URLProtocol-replay implementation; this test pins that the leak is gone. + /// `FakeServerProtocol` returns a `Set-Cookie` header for `/cookie-test`, so the assertion would + /// fail loudly if cookies started flowing into the shared jar again. @Test func `does not leak cookies from an ephemeral session into the shared storage`() async throws { // Wipe any cookie a previous test or stray network state might have planted on `fake.test`. @@ -531,12 +530,10 @@ struct NetworkRequestTaskSwizzlingTests { #expect(sharedAfter.isEmpty) } - /** - `URLSessionWebSocketTask` extends `URLSessionTask` so the swizzle's `resume` fires on it, but - websockets don't produce useful HTTP metrics and we deliberately skip them. We resume a - websocket task pointed at a URL that will never connect, then cancel it; the swizzle must not - have recorded a snapshot. - */ + /// `URLSessionWebSocketTask` extends `URLSessionTask` so the swizzle's `resume` fires on it, but + /// websockets don't produce useful HTTP metrics and we deliberately skip them. We resume a + /// websocket task pointed at a URL that will never connect, then cancel it; the swizzle must not + /// have recorded a snapshot. @Test func `skips websocket tasks`() async throws { let config = URLSessionConfiguration.ephemeral @@ -553,12 +550,10 @@ struct NetworkRequestTaskSwizzlingTests { #expect(recorded == nil) } - /** - Requests marked with `ExpoRequestInterceptorProtocol.requestId` are dev-launcher inner replays — - the swizzle must skip them so we don't double-record every request in dev-client builds. Drive - the check through `URLProtocol.setProperty(_:forKey:in:)` directly; we don't need the - dev-launcher itself to repro the condition. - */ + /// Requests marked with `ExpoRequestInterceptorProtocol.requestId` are dev-launcher inner replays — + /// the swizzle must skip them so we don't double-record every request in dev-client builds. Drive + /// the check through `URLProtocol.setProperty(_:forKey:in:)` directly; we don't need the + /// dev-launcher itself to repro the condition. @Test func `skips dev-launcher inner replay tasks`() async throws { let config = URLSessionConfiguration.ephemeral @@ -577,12 +572,10 @@ struct NetworkRequestTaskSwizzlingTests { #expect(recorded == nil) } - /** - Sessions created without a delegate (and the global `URLSession.shared`-style completion-handler - path) skip our `DelegateProxy`, so `didFinishCollectingMetrics:` never fires. The `setState:` - fallback has to win after `setStateFallbackDelay` and still record the snapshot — degraded (no - per-phase metrics) but present. - */ + /// Sessions created without a delegate (and the global `URLSession.shared`-style completion-handler + /// path) skip our `DelegateProxy`, so `didFinishCollectingMetrics:` never fires. The `setState:` + /// fallback has to win after `setStateFallbackDelay` and still record the snapshot — degraded (no + /// per-phase metrics) but present. @Test func `records delegate-less sessions via the setState fallback`() async throws { let config = URLSessionConfiguration.ephemeral @@ -625,12 +618,10 @@ struct NetworkRequestTaskSwizzlingTests { } } -/** - The JS-facing observer mostly forwards to `NetworkRequestMonitor`, which is exercised by the - `NetworkRequestMonitor` suite. What's specific to the observer is the payload shape — the dict - it hands to `emit()` is the wire format JS consumers see. These tests pin that shape down so - renames (`fromUrl` → `from`, `responseEnd` → `endedAt`, etc.) require a deliberate change. - */ +/// The JS-facing observer mostly forwards to `NetworkRequestMonitor`, which is exercised by the +/// `NetworkRequestMonitor` suite. What's specific to the observer is the payload shape — the dict +/// it hands to `emit()` is the wire format JS consumers see. These tests pin that shape down so +/// renames (`fromUrl` → `from`, `responseEnd` → `endedAt`, etc.) require a deliberate change. @Suite("NetworkRequestObserver") struct NetworkRequestObserverTests { @Test @@ -805,8 +796,8 @@ private final class CollectingDelegate: NetworkRequestObserverDelegate, @uncheck } } -/** Collecting delegate that only accepts requests for a single host, exercising the monitor's - per-delegate `shouldObserveRequest` consult at the fan-out site. */ +/// Collecting delegate that only accepts requests for a single host, exercising the monitor's +/// per-delegate `shouldObserveRequest` consult at the fan-out site. private final class FilteringDelegate: NetworkRequestObserverDelegate, @unchecked Sendable { private let allowedHost: String private let lock = NSLock() @@ -854,14 +845,12 @@ private final class FilteringDelegate: NetworkRequestObserverDelegate, @unchecke } } -/** - A trivial `URLProtocol` that pretends to be a server. Routes by URL path: - - `/cookie-test` returns a `Set-Cookie` header so the cookie-isolation test can detect a leak. - - any other path echoes the request body back when there is one (POST/PUT payload assertions) and - otherwise returns a `hi` body. - - Sits at the tail of the protocol chain in the test's outer session. - */ +/// A trivial `URLProtocol` that pretends to be a server. Routes by URL path: +/// - `/cookie-test` returns a `Set-Cookie` header so the cookie-isolation test can detect a leak. +/// - any other path echoes the request body back when there is one (POST/PUT payload assertions) and +/// otherwise returns a `hi` body. +/// +/// Sits at the tail of the protocol chain in the test's outer session. private final class FakeServerProtocol: URLProtocol { override class func canInit(with request: URLRequest) -> Bool { return request.url?.host == "fake.test" @@ -873,7 +862,8 @@ private final class FakeServerProtocol: URLProtocol { override func startLoading() { let url = request.url! - let headers: [String: String]? = url.path == "/cookie-test" + let headers: [String: String]? = + url.path == "/cookie-test" ? ["Set-Cookie": "fake=value; Path=/"] : nil let response = HTTPURLResponse(url: url, statusCode: 200, httpVersion: "HTTP/1.1", headerFields: headers)! @@ -885,11 +875,9 @@ private final class FakeServerProtocol: URLProtocol { override func stopLoading() {} - /** - Reads the request body, preferring the in-memory `httpBody` and falling back to draining - `httpBodyStream` — by the time a request reaches a `URLProtocol`, Foundation has usually - converted the body to a stream, which is exactly the path we want to exercise. - */ + /// Reads the request body, preferring the in-memory `httpBody` and falling back to draining + /// `httpBodyStream` — by the time a request reaches a `URLProtocol`, Foundation has usually + /// converted the body to a stream, which is exactly the path we want to exercise. private static func readBody(from request: URLRequest) -> Data? { if let body = request.httpBody { return body diff --git a/packages/expo-app-metrics/ios/Updates/UpdatesMonitoring.swift b/packages/expo-app-metrics/ios/Updates/UpdatesMonitoring.swift index 393a459a9348af..41da90d2a814b5 100644 --- a/packages/expo-app-metrics/ios/Updates/UpdatesMonitoring.swift +++ b/packages/expo-app-metrics/ios/Updates/UpdatesMonitoring.swift @@ -1,11 +1,10 @@ -import ExpoModulesCore import EXUpdatesInterface +import ExpoModulesCore +// swift-format-ignore: AlwaysUseLowerCamelCase let MAX_CACHED_EVENTS = 50 -/** - Encapsulate updates monitoring in this class - */ +/// Encapsulate updates monitoring in this class @AppMetricsActor internal class UpdatesMonitoring: MetricReporter { private var launchedUpdateId: String? @@ -33,7 +32,8 @@ internal class UpdatesMonitoring: MetricReporter { requestHeadersJSON: encodeAsJSONString(updatesInfo.requestHeaders) ) } catch { - logger.warn("[AppMetrics] Failed to patch app updates info on active sessions: \(error.localizedDescription)") + logger.warn( + "[AppMetrics] Failed to patch app updates info on active sessions: \(error.localizedDescription)") } } } @@ -52,7 +52,8 @@ internal class UpdatesMonitoring: MetricReporter { let embeddedUpdateId = updatesController.embeddedUpdateId // Ignore embedded launches – they are not available on the website anyway. - let updateId = launchedUpdateId == embeddedUpdateId + let updateId = + launchedUpdateId == embeddedUpdateId ? nil : launchedUpdateId?.uuidString.lowercased() let runtimeVersion = updatesController.runtimeVersion @@ -66,10 +67,11 @@ internal class UpdatesMonitoring: MetricReporter { nonisolated func downloadTimeMetric(_ subscription: UpdatesStateChangeSubscription?) -> Metric? { guard let subscription, - let context = subscription.getContext() as? UpdatesNativeInterfaceStateContext, - let updateId = context.downloadedManifest?["id"] as? String, - let startTime = context.downloadStartTime, - let finishTime = context.downloadFinishTime else { + let context = subscription.getContext() as? UpdatesNativeInterfaceStateContext, + let updateId = context.downloadedManifest?["id"] as? String, + let startTime = context.downloadStartTime, + let finishTime = context.downloadFinishTime + else { return nil } let lastDownloadTime = finishTime.timeIntervalSince(startTime) diff --git a/packages/expo-app-metrics/ios/Utils/AnyCodable.swift b/packages/expo-app-metrics/ios/Utils/AnyCodable.swift index 19bcd8936569da..ea23a06f1d7312 100644 --- a/packages/expo-app-metrics/ios/Utils/AnyCodable.swift +++ b/packages/expo-app-metrics/ios/Utils/AnyCodable.swift @@ -1,6 +1,4 @@ -/** - Type-erased struct that is used to encode/decode types that use `Any` which itself is not conforming to `Encodable` nor `Decodable`. - */ +/// Type-erased struct that is used to encode/decode types that use `Any` which itself is not conforming to `Encodable` nor `Decodable`. public struct AnyCodable: Codable, Sendable { // Similarly, `Any` does not conform to `Sendable`, but it is safe // to send it over different isolation domains as it is immutable. diff --git a/packages/expo-app-metrics/ios/Utils/DeviceConditions.swift b/packages/expo-app-metrics/ios/Utils/DeviceConditions.swift index de2bb4ac6e7a38..0411d5a56168bb 100644 --- a/packages/expo-app-metrics/ios/Utils/DeviceConditions.swift +++ b/packages/expo-app-metrics/ios/Utils/DeviceConditions.swift @@ -2,16 +2,12 @@ import ExpoModulesCore -/** - A `Sendable` snapshot of the device's power and thermal state. Fields are - optional so missing OS data (Simulator, brief windows where the OS hasn't - published a value yet) can be expressed as `nil` rather than a sentinel. - */ +/// A `Sendable` snapshot of the device's power and thermal state. Fields are +/// optional so missing OS data (Simulator, brief windows where the OS hasn't +/// published a value yet) can be expressed as `nil` rather than a sentinel. struct DeviceState: Sendable, Equatable { - /** - The raw values are part of the `expo.device.thermalState` wire contract - — `MetricParamsBuilder` emits them via `.rawValue`. Don't rename cases. - */ + /// The raw values are part of the `expo.device.thermalState` wire contract + /// — `MetricParamsBuilder` emits them via `.rawValue`. Don't rename cases. enum ThermalState: String, Sendable { case nominal case fair @@ -26,36 +22,32 @@ struct DeviceState: Sendable, Equatable { let batteryCharging: Bool? } -/** - Reads the device's environment (power, thermals, battery) into a typed - `DeviceState`. The wire-format conversion to `expo.*` keys lives in - `MetricParamsBuilder`. - */ +/// Reads the device's environment (power, thermals, battery) into a typed +/// `DeviceState`. The wire-format conversion to `expo.*` keys lives in +/// `MetricParamsBuilder`. enum DeviceConditions { - /** - Reads device power, thermal, and battery state. Returned fields are `nil` - when the OS does not report a meaningful value — typically the Simulator, - or the brief window after battery monitoring is first enabled before the - first reading is published. - - Pinned to `@MainActor` because `UIDevice` is part of UIKit and its - battery state/level reads are not documented as thread-safe. `ProcessInfo` - reads (low-power mode, thermal state) are thread-safe in isolation, but - we pin the whole helper for simplicity at the cost of one main-actor hop. - */ + /// Reads device power, thermal, and battery state. Returned fields are `nil` + /// when the OS does not report a meaningful value — typically the Simulator, + /// or the brief window after battery monitoring is first enabled before the + /// first reading is published. + /// + /// Pinned to `@MainActor` because `UIDevice` is part of UIKit and its + /// battery state/level reads are not documented as thread-safe. `ProcessInfo` + /// reads (low-power mode, thermal state) are thread-safe in isolation, but + /// we pin the whole helper for simplicity at the cost of one main-actor hop. @MainActor static func deviceState() -> DeviceState { let lowPowerMode = ProcessInfo.processInfo.isLowPowerModeEnabled let thermalState = thermalState(from: ProcessInfo.processInfo.thermalState) -#if os(tvOS) + #if os(tvOS) return DeviceState( lowPowerMode: lowPowerMode, thermalState: thermalState, batteryLevel: nil, batteryCharging: nil ) -#else + #else // tvOS devices are wall-powered, so `UIDevice` doesn't expose battery // state/level there; the `#if` skips the battery section entirely. let device = UIDevice.current @@ -73,12 +65,13 @@ enum DeviceConditions { let level = device.batteryLevel let batteryLevel: Double? = level >= 0 ? Double(level) : nil - let batteryCharging: Bool? = switch device.batteryState { - case .charging, .full: true - case .unplugged: false - case .unknown: nil - @unknown default: nil - } + let batteryCharging: Bool? = + switch device.batteryState { + case .charging, .full: true + case .unplugged: false + case .unknown: nil + @unknown default: nil + } return DeviceState( lowPowerMode: lowPowerMode, @@ -86,7 +79,7 @@ enum DeviceConditions { batteryLevel: batteryLevel, batteryCharging: batteryCharging ) -#endif + #endif } private static func thermalState(from state: ProcessInfo.ThermalState) -> DeviceState.ThermalState { diff --git a/packages/expo-app-metrics/ios/Utils/JSONCoding.swift b/packages/expo-app-metrics/ios/Utils/JSONCoding.swift index de6a965f66007d..6fc429a5399f05 100644 --- a/packages/expo-app-metrics/ios/Utils/JSONCoding.swift +++ b/packages/expo-app-metrics/ios/Utils/JSONCoding.swift @@ -2,10 +2,8 @@ import Foundation -/** - Encodes any `Encodable` value as a UTF-8 JSON string using ISO-8601 dates. Returns nil when - encoding fails (a warning is logged) or when the bytes aren't valid UTF-8. - */ +/// Encodes any `Encodable` value as a UTF-8 JSON string using ISO-8601 dates. Returns nil when +/// encoding fails (a warning is logged) or when the bytes aren't valid UTF-8. func encodeAsJSONString(_ value: T) -> String? { let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 @@ -18,10 +16,8 @@ func encodeAsJSONString(_ value: T) -> String? { } } -/** - Encodes a plain `[String: String]` dictionary as a UTF-8 JSON string. Cheaper than routing through - `Codable` when the shape is fixed. - */ +/// Encodes a plain `[String: String]` dictionary as a UTF-8 JSON string. Cheaper than routing through +/// `Codable` when the shape is fixed. func encodeAsJSONString(_ value: [String: String]?) -> String? { guard let value, let data = try? JSONSerialization.data(withJSONObject: value) else { return nil @@ -29,10 +25,8 @@ func encodeAsJSONString(_ value: [String: String]?) -> String? { return String(data: data, encoding: .utf8) } -/** - Decodes a JSON-string column into a `[String: V]` dictionary, or nil when the string is missing or - doesn't represent a JSON object of the expected shape. - */ +/// Decodes a JSON-string column into a `[String: V]` dictionary, or nil when the string is missing or +/// doesn't represent a JSON object of the expected shape. func decodeJSONDictionary(_ json: String?) -> [String: V]? { guard let json, let data = json.data(using: .utf8) else { return nil @@ -40,11 +34,9 @@ func decodeJSONDictionary(_ json: String?) -> [String: V]? { return try? JSONSerialization.jsonObject(with: data) as? [String: V] } -/** - Decodes a JSON-string column into the requested `Decodable` type using ISO-8601 dates. Returns nil - when the column is absent or the payload is malformed (a warning is logged in the latter case). - Symmetric with `encodeAsJSONString(_:)`. - */ +/// Decodes a JSON-string column into the requested `Decodable` type using ISO-8601 dates. Returns nil +/// when the column is absent or the payload is malformed (a warning is logged in the latter case). +/// Symmetric with `encodeAsJSONString(_:)`. func decodeFromJSONString(_ type: T.Type, from json: String?) -> T? { guard let json, let data = json.data(using: .utf8) else { return nil diff --git a/packages/expo-app-metrics/ios/Utils/MetricParamsBuilder.swift b/packages/expo-app-metrics/ios/Utils/MetricParamsBuilder.swift index 21bf6b1e0c2ca8..43228533e5ded9 100644 --- a/packages/expo-app-metrics/ios/Utils/MetricParamsBuilder.swift +++ b/packages/expo-app-metrics/ios/Utils/MetricParamsBuilder.swift @@ -2,20 +2,16 @@ import Foundation -/** - Single source of truth for the `expo.*` keys we attach to metrics. Takes - typed inputs (`DeviceState`, `NetworkPath`, `FrameRateMetrics`) and produces - the flat `[String: Any]` map the metric envelope expects. - - Framework-emitted keys override user-supplied keys on collision so the OS - readings always win — a user passing `expo.device.lowPowerMode: "yes"` - doesn't get to overwrite the actual OS bool. - */ +/// Single source of truth for the `expo.*` keys we attach to metrics. Takes +/// typed inputs (`DeviceState`, `NetworkPath`, `FrameRateMetrics`) and produces +/// the flat `[String: Any]` map the metric envelope expects. +/// +/// Framework-emitted keys override user-supplied keys on collision so the OS +/// readings always win — a user passing `expo.device.lowPowerMode: "yes"` +/// doesn't get to overwrite the actual OS bool. enum MetricParamsBuilder { - /** - Builds the params map for a metric. All inputs are optional; any input - that is `nil` simply contributes no keys. - */ + /// Builds the params map for a metric. All inputs are optional; any input + /// that is `nil` simply contributes no keys. static func build( userParams: [String: Any] = [:], frameMetrics: FrameRateMetrics? = nil, diff --git a/packages/expo-app-metrics/ios/Utils/Sysctl.swift b/packages/expo-app-metrics/ios/Utils/Sysctl.swift index 437e6a516b33a8..194242f6766375 100644 --- a/packages/expo-app-metrics/ios/Utils/Sysctl.swift +++ b/packages/expo-app-metrics/ios/Utils/Sysctl.swift @@ -1,12 +1,8 @@ import Darwin.sys.sysctl -/** - Contains utils that call into kernel's `sysctl` function. - */ +/// Contains utils that call into kernel's `sysctl` function. internal struct Sysctl { - /** - Returns seconds since Unix epoch (January 1, 1970) when the device booted. - */ + /// Returns seconds since Unix epoch (January 1, 1970) when the device booted. static func getSystemBootTime() -> TimeInterval { var mib: [Int32] = [CTL_KERN, KERN_BOOTTIME] var bootTime = timeval() diff --git a/packages/expo-app-metrics/package.json b/packages/expo-app-metrics/package.json index 5aa317a09b5941..265e1b076ada98 100644 --- a/packages/expo-app-metrics/package.json +++ b/packages/expo-app-metrics/package.json @@ -10,6 +10,8 @@ "build": "expo-module build", "clean": "expo-module clean", "lint": "expo-module lint", + "swift:format": "../../scripts/swift-format.sh", + "swift:lint": "../../scripts/swift-format.sh --lint", "test": "expo-module test", "prepublishOnly": "expo-module prepublishOnly", "expo-module": "expo-module" diff --git a/packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh b/packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh index 6da19534862c99..cb27a834a878d9 100755 --- a/packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh +++ b/packages/expo-brownfield/e2e/scripts/run-e2e-ios.sh @@ -6,7 +6,10 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" # Setup simulator source $DIR/setup-simulator.sh -start_simulator +if ! start_simulator || [[ -z "$DEVICE_ID" ]]; then + echo " ❌ Could not find or boot the target iOS simulator. Check that the runtime is installed (xcrun simctl list runtimes) and matches DEVICE/IOS_VERSION in setup-simulator.sh." + exit 1 +fi # Install app source $DIR/install-app-ios.sh $DEVICE_ID diff --git a/packages/expo-brownfield/e2e/scripts/setup-simulator.sh b/packages/expo-brownfield/e2e/scripts/setup-simulator.sh index fee0d9e40a14f0..9b3a694dc73866 100755 --- a/packages/expo-brownfield/e2e/scripts/setup-simulator.sh +++ b/packages/expo-brownfield/e2e/scripts/setup-simulator.sh @@ -33,7 +33,7 @@ function start_simulator() { echo " 🔍 Looking for device: $DEVICE with iOS version: $IOS_VERSION..." - DEVICE_ID=$(xcrun simctl list devices iPhone available --json | jq -r --arg device "$DEVICE" --arg ios_version "$IOS_VERSION" '.devices | to_entries[] | select(.key | contains("com.apple.CoreSimulator.SimRuntime.iOS-" + $ios_version + "-2")) | .value[] | select(.name == $device) | .udid' | head -n1) + DEVICE_ID=$(xcrun simctl list devices iPhone available --json | jq -r --arg device "$DEVICE" --arg ios_version "$IOS_VERSION" '.devices | to_entries[] | select(.key | contains("com.apple.CoreSimulator.SimRuntime.iOS-" + $ios_version + "-")) | .value[] | select(.name == $device) | .udid' | head -n1) if [[ -z "$DEVICE_ID" ]]; then echo " ⚠️ No device found for $DEVICE with iOS $IOS_VERSION" return 1 diff --git a/packages/expo-brownfield/e2e/utils/process.ts b/packages/expo-brownfield/e2e/utils/process.ts index 43bce36749eb57..0a82da959934af 100644 --- a/packages/expo-brownfield/e2e/utils/process.ts +++ b/packages/expo-brownfield/e2e/utils/process.ts @@ -1,4 +1,4 @@ -import spawnAsync from '@expo/spawn-async'; +import spawnAsync, { SpawnResult } from '@expo/spawn-async'; export const CLI_PATH = require.resolve('../../bin/cli.js'); export const CREATE_EXPO_BIN = require.resolve('create-expo/bin/create-expo.js'); @@ -10,79 +10,34 @@ export interface ExecuteCLIOptions { /** * Execute the CLI */ -export const executeCLIASync = async ( +export const executeCLIASync = ( cwd: string, args: string[], options: ExecuteCLIOptions = { ignoreErrors: false } ) => { - try { - const { stdout, stderr, status } = await spawnAsync(CLI_PATH, args, { - cwd, - stdio: 'pipe', - }); - - return processOutput({ stdout, stderr, status }); - } catch (error) { - if (!options.ignoreErrors) { - console.error(error); - throw error; - } - - const { stdout, stderr, status } = error; - return processOutput({ stdout, stderr, status }); - } + return executeCommandAsync(cwd, CLI_PATH, args, options); }; /** * Execute Expo CLI */ -export const executeExpoCLIAsync = async ( +export const executeExpoCLIAsync = ( cwd: string, args: string[], options: ExecuteCLIOptions = { ignoreErrors: false } ) => { - try { - const { stdout, stderr, status } = await spawnAsync('pnpm', ['expo', ...args], { - cwd, - stdio: 'pipe', - }); - - return processOutput({ stdout, stderr, status }); - } catch (error) { - if (!options.ignoreErrors) { - console.error(error); - throw error; - } - - const { stdout, stderr, status } = error; - return processOutput({ stdout, stderr, status }); - } + return executeCommandAsync(cwd, 'pnpm', ['expo', ...args], options); }; /** * Execute Create Expo CLI */ -export const executeCreateExpoCLIAsync = async ( +export const executeCreateExpoCLIAsync = ( cwd: string, args: string[], options: ExecuteCLIOptions = { ignoreErrors: false } ) => { - try { - const { stdout, stderr, status } = await spawnAsync(CREATE_EXPO_BIN, args, { - cwd, - stdio: 'pipe', - }); - - return processOutput({ stdout, stderr, status }); - } catch (error) { - if (!options.ignoreErrors) { - console.error(error); - throw error; - } - - const { stdout, stderr, status } = error; - return processOutput({ stdout, stderr, status }); - } + return executeCommandAsync(cwd, CREATE_EXPO_BIN, args, options); }; /** @@ -102,12 +57,19 @@ export const executeCommandAsync = async ( return processOutput({ stdout, stderr, status }); } catch (error) { + const { stdout, stderr, status } = error as SpawnResult; + if (!options.ignoreErrors) { - console.error(error); + console.error(`Command "${[command, ...args].join(' ')}" exited with code ${status ?? 1}`); + if (stdout) { + console.error(`stdout:\n${stripAnsi(stdout)}`); + } + if (stderr) { + console.error(`stderr:\n${stripAnsi(stderr)}`); + } throw error; } - const { stdout, stderr, status } = error; return processOutput({ stdout, stderr, status }); } }; diff --git a/packages/expo-brownfield/e2e/utils/project.ts b/packages/expo-brownfield/e2e/utils/project.ts index 12b17c56fd8f8a..7025bd83eed429 100644 --- a/packages/expo-brownfield/e2e/utils/project.ts +++ b/packages/expo-brownfield/e2e/utils/project.ts @@ -138,11 +138,11 @@ const listWorkspaces = async (): Promise> => { const { stdout } = await spawnAsync('pnpm', ['list', '--depth=-1', '-r', '--json'], { cwd: path.join(__dirname, '../../'), }); - const workspaces: { name: string; path: string; }[] = JSON.parse(stdout); - return workspaces.reduce((acc, entry) => { + const workspaces: { name: string; path: string }[] = JSON.parse(stdout); + return workspaces.reduce>((acc, entry) => { acc[entry.name] = entry.path; return acc; - }, {} as Record); + }, {}); }; /** diff --git a/packages/expo-camera/CHANGELOG.md b/packages/expo-camera/CHANGELOG.md index 9fdcdf9908d351..8073bbb0c699e5 100644 --- a/packages/expo-camera/CHANGELOG.md +++ b/packages/expo-camera/CHANGELOG.md @@ -8,6 +8,8 @@ ### 🐛 Bug fixes +- [Android] Use the selected camera to determine video stabilization support. ([#45896](https://github.com/expo/expo/pull/45896) by [@vivekjm](https://github.com/vivekjm)) + ### 💡 Others ## 56.0.7 — 2026-05-21 diff --git a/packages/expo-camera/android/src/main/java/expo/modules/camera/ExpoCameraView.kt b/packages/expo-camera/android/src/main/java/expo/modules/camera/ExpoCameraView.kt index d9690e37ebf047..51489815b220b2 100644 --- a/packages/expo-camera/android/src/main/java/expo/modules/camera/ExpoCameraView.kt +++ b/packages/expo-camera/android/src/main/java/expo/modules/camera/ExpoCameraView.kt @@ -494,7 +494,10 @@ class ExpoCameraView( imageCaptureUseCase = imageCaptureBuilder.build() - val videoCapture = createVideoCapture() + val selectedCameraInfo = cameraSelector + .filter(cameraProvider.availableCameraInfos) + .firstOrNull() + val videoCapture = createVideoCapture(selectedCameraInfo) imageAnalysisUseCase = createImageAnalyzer() val useCases = UseCaseGroup.Builder().apply { @@ -590,7 +593,7 @@ class ExpoCameraView( } } - private fun createVideoCapture(): VideoCapture { + private fun createVideoCapture(cameraInfo: CameraInfo?): VideoCapture { val preferredQuality = videoQuality.mapToQuality() val fallbackStrategy = FallbackStrategy.higherQualityOrLowerThan(preferredQuality) val qualitySelector = QualitySelector.from(preferredQuality, fallbackStrategy) @@ -611,10 +614,18 @@ class ExpoCameraView( if (mirror) { setMirrorMode(MirrorMode.MIRROR_MODE_ON_FRONT_ONLY) } - setVideoStabilizationEnabled(videoStabilizationMode.isEnabled()) + setVideoStabilizationEnabled(isVideoStabilizationEnabled(cameraInfo)) }.build() } + private fun isVideoStabilizationEnabled(cameraInfo: CameraInfo?): Boolean { + val isStabilizationSupported = cameraInfo?.let { + Recorder.getVideoCapabilities(it).isStabilizationSupported + } ?: false + + return isStabilizationSupported && videoStabilizationMode.isEnabled() + } + private fun startFocusMetering() { camera?.let { val meteringPointFactory = DisplayOrientedMeteringPointFactory( diff --git a/packages/expo-dev-launcher/CHANGELOG.md b/packages/expo-dev-launcher/CHANGELOG.md index 2bd3ec7b3ef620..8d1817defb575b 100644 --- a/packages/expo-dev-launcher/CHANGELOG.md +++ b/packages/expo-dev-launcher/CHANGELOG.md @@ -16,6 +16,7 @@ - [iOS] Improve the Updates tab empty state with clearer guidance on how to publish an update. ([#46759](https://github.com/expo/expo/pull/46759) by [@alanjhughes](https://github.com/alanjhughes)) - [iOS] Present the development server info dialog as a native sheet. ([#46760](https://github.com/expo/expo/pull/46760) by [@alanjhughes](https://github.com/alanjhughes)) - [iOS] Reduce accidental logout in the account selector with a confirmation step and a less prominent button, and add more spacing around the header title. ([#46761](https://github.com/expo/expo/pull/46761) by [@alanjhughes](https://github.com/alanjhughes)) +- [iOS] Make the development server list reliable, keep discovery running across tab switches, periodically re-verify discovered servers, add pull-to-refresh on the Home tab, and show a searching state instead of "No development servers found". ([#46811](https://github.com/expo/expo/pull/46811) by [@alanjhughes](https://github.com/alanjhughes)) ### 💡 Others diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewModel.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewModel.swift index e99832621cf7d8..c918df905e36c2 100644 --- a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewModel.swift +++ b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViewModel.swift @@ -62,6 +62,9 @@ class DevLauncherViewModel: ObservableObject { private var browser: NWBrowser? private var pingTask: Task? + private var periodicRefreshTask: Task? + private var pendingEmptyVerification = false + private static let refreshInterval: UInt64 = 10_000_000_000 #if !os(tvOS) private let presentationContext = DevLauncherAuthPresentationContext() @@ -97,6 +100,16 @@ class DevLauncherViewModel: ObservableObject { } private func updateDevServers(_ servers: [DevServer]) { + if servers.isEmpty && !devServers.isEmpty && !pendingEmptyVerification { + pendingEmptyVerification = true + stopServerDiscovery() + startServerDiscovery() + return + } + pendingEmptyVerification = false + if !servers.isEmpty { + markNetworkPermissionGranted() + } devServers = servers.sorted(by: <) } @@ -204,9 +217,65 @@ class DevLauncherViewModel: ObservableObject { stopServerDiscovery() startDevServerBrowser() + startPeriodicRefresh() + } + + func refreshDevServers() async { + await restartBrowser() + } + + private func restartBrowser() async { + pingTask?.cancel() + browser?.cancel() + pingTask = nil + browser = nil + startDevServerBrowser() + try? await Task.sleep(nanoseconds: 3_000_000_000) + await pingCurrentBrowseResults() + } + + private func pingCurrentBrowseResults() async { + guard let browser, !browser.browseResults.isEmpty else { + return + } + await pingDiscoveryResults(browser.browseResults.map { result in + DiscoveryResult( + name: NetworkUtilities.getNWBrowserResultName(result), + endpoint: result.endpoint + ) + }) + } + + private func startPeriodicRefresh() { + periodicRefreshTask?.cancel() + periodicRefreshTask = Task { [weak self] in + while !Task.isCancelled { + try? await Task.sleep(nanoseconds: Self.refreshInterval) + guard !Task.isCancelled else { + return + } + await self?.refreshIfNeeded() + } + } + } + + private func refreshIfNeeded() async { + guard let browser else { + return + } + if devServers.isEmpty { + await restartBrowser() + } else if browser.browseResults.isEmpty { + updateDevServers([]) + } else { + await pingCurrentBrowseResults() + } } func markNetworkPermissionGranted() { + guard permissionStatus != .granted else { + return + } UserDefaults.standard.set(true, forKey: networkPermissionGrantedKey) permissionStatus = .granted } @@ -272,8 +341,10 @@ class DevLauncherViewModel: ObservableObject { } func stopServerDiscovery() { + periodicRefreshTask?.cancel() pingTask?.cancel() browser?.cancel() + periodicRefreshTask = nil pingTask = nil browser = nil } diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift index f038eaa710f921..24ba2b59fd8f08 100644 --- a/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift +++ b/packages/expo-dev-launcher/ios/SwiftUI/DevLauncherViews.swift @@ -76,6 +76,12 @@ public struct DevLauncherRootView: View { #endif navigationStack + .onAppear { + viewModel.startServerDiscovery() + } + .onDisappear { + viewModel.stopServerDiscovery() + } .sheet(isPresented: $showingUserProfile) { AccountSheet() .environmentObject(viewModel) diff --git a/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift b/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift index f29edd3ed25cc7..5e86a01b391368 100644 --- a/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift +++ b/packages/expo-dev-launcher/ios/SwiftUI/DevServersView.swift @@ -49,11 +49,17 @@ struct DevServersView: View { LazyVStack(alignment: .leading, spacing: 6) { if viewModel.devServers.isEmpty { - Text("No development servers found") - .foregroundColor(.primary) - .multilineTextAlignment(.leading) + if viewModel.permissionStatus != .denied { + HStack { + Text("Searching for development servers...") + .foregroundColor(.secondary) + Spacer() + ProgressView() + .controlSize(.small) + } .padding() - Divider() + Divider() + } } else { ForEach(viewModel.devServers, id: \.self) { server in DevServerRow(server: server) { @@ -67,12 +73,6 @@ struct DevServersView: View { enterUrl } } - .onAppear { - viewModel.startServerDiscovery() - } - .onDisappear { - viewModel.stopServerDiscovery() - } } private var enterUrl: some View { diff --git a/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift b/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift index f785bbeaa1d40c..abf5e0b595feb1 100644 --- a/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift +++ b/packages/expo-dev-launcher/ios/SwiftUI/HomeTabView.swift @@ -55,6 +55,11 @@ struct HomeTabView: View { } .padding() } + #if !os(tvOS) + .refreshable { + await viewModel.refreshDevServers() + } + #endif } #if os(tvOS) .background() diff --git a/packages/expo-media-library/CHANGELOG.md b/packages/expo-media-library/CHANGELOG.md index 207289ccec0576..d0c0c264f4db56 100644 --- a/packages/expo-media-library/CHANGELOG.md +++ b/packages/expo-media-library/CHANGELOG.md @@ -13,6 +13,8 @@ ### 💡 Others +- Re-organize TS code ([#45953](https://github.com/expo/expo/pull/45953) by [@Wenszel](https://github.com/Wenszel)) + ## 56.0.6 — 2026-05-21 ### 🐛 Bug fixes diff --git a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/asset/domain/MediaStoreAudio.kt b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/asset/domain/MediaStoreAudio.kt index 3a4a47b38cbf1d..540b5e4a3d6a8c 100644 --- a/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/asset/domain/MediaStoreAudio.kt +++ b/packages/expo-media-library/android/src/main/java/expo/modules/medialibrary/next/objects/asset/domain/MediaStoreAudio.kt @@ -26,7 +26,7 @@ data class MediaStoreAudio( displayName = getNullableString(columnIndexes.displayName), dateTaken = getNullableLong(columnIndexes.dateTaken), dateModified = getNullableLong(columnIndexes.dateModified), - duration = getNullableLong(columnIndexes.duration), + duration = getNullableLong(columnIndexes.duration), data = getNullableString(columnIndexes.data), isFavorite = columnIndexes.isFavorite?.let { getNullableInt(it) } ) diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.d.ts.map b/packages/expo-media-library/build/ExpoMediaLibrary.d.ts.map deleted file mode 100644 index b9100ab686239b..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibrary.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibrary.d.ts","sourceRoot":"","sources":["../src/ExpoMediaLibrary.ts"],"names":[],"mappings":";AACA,wBAAuD"} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.js.map b/packages/expo-media-library/build/ExpoMediaLibrary.js.map deleted file mode 100644 index 8eceb90dabe8ff..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibrary.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibrary.js","sourceRoot":"","sources":["../src/ExpoMediaLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,eAAe,mBAAmB,CAAC,kBAAkB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nexport default requireNativeModule('ExpoMediaLibrary');\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts.map b/packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts.map deleted file mode 100644 index 241b2e84a68d0a..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibrary.web.d.ts","sourceRoot":"","sources":["../src/ExpoMediaLibrary.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAoB,MAAM,MAAM,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;;mCAU7C,MAAM;wBAGjB,eAAe;qBAQlB,YAAY;oCAYY,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;wCAGjC,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;;AA3BjF,wBA8BE"} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.web.js.map b/packages/expo-media-library/build/ExpoMediaLibrary.web.js.map deleted file mode 100644 index b2b53fa565aeac..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibrary.web.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibrary.web.js","sourceRoot":"","sources":["../src/ExpoMediaLibrary.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAIjE,MAAM,oBAAoB,GAAuB;IAC/C,MAAM,EAAE,gBAAgB,CAAC,YAAY;IACrC,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF,eAAe;IACb,IAAI,oBAAoB;QACtB,OAAO,uBAAuB,CAAC;IACjC,CAAC;IACD,IAAI,SAAS;QACX,OAAO;YACL,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,SAAS;SACnB,CAAC;IACJ,CAAC;IACD,IAAI,MAAM;QACR,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,QAAQ;YAChB,YAAY,EAAE,cAAc;YAC5B,gBAAgB,EAAE,kBAAkB;YACpC,QAAQ,EAAE,UAAU;SACrB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,UAAmB;QAC3C,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,uBAAuB,CAAC,UAAmB;QAC/C,OAAO,oBAAoB,CAAC;IAC9B,CAAC;CACF,CAAC","sourcesContent":["import { type PermissionResponse, PermissionStatus } from 'expo';\n\nimport type { MediaTypeObject, SortByObject } from './legacy/MediaLibrary';\n\nconst noPermissionResponse: PermissionResponse = {\n status: PermissionStatus.UNDETERMINED,\n canAskAgain: true,\n granted: false,\n expires: 'never',\n};\n\nexport default {\n get CHANGE_LISTENER_NAME(): string {\n return 'mediaLibraryDidChange';\n },\n get MediaType(): MediaTypeObject {\n return {\n audio: 'audio',\n photo: 'photo',\n video: 'video',\n unknown: 'unknown',\n };\n },\n get SortBy(): SortByObject {\n return {\n default: 'default',\n mediaType: 'mediaType',\n width: 'width',\n height: 'height',\n creationTime: 'creationTime',\n modificationTime: 'modificationTime',\n duration: 'duration',\n };\n },\n\n async getPermissionsAsync(_writeOnly: boolean): Promise {\n return noPermissionResponse;\n },\n async requestPermissionsAsync(_writeOnly: boolean): Promise {\n return noPermissionResponse;\n },\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts b/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts deleted file mode 100644 index 077bf93864e147..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { PermissionResponse } from 'expo'; -import { NativeModule } from 'expo-modules-core'; -import type { GranularPermission, MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types'; -import { Album } from './types/Album'; -import { Asset } from './types/Asset'; -import type { MediaTypeFilter } from './types/MediaTypeFilter'; -import { Query } from './types/Query'; -declare class ExpoMediaLibraryNextModule extends NativeModule<{ - mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void; -}> { - Asset: typeof Asset; - Album: typeof Album; - Query: typeof Query; - getPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; - requestPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; - presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; -} -declare const _default: ExpoMediaLibraryNextModule; -export default _default; -//# sourceMappingURL=ExpoMediaLibraryNext.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts.map b/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts.map deleted file mode 100644 index 111d66e3089efc..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibraryNext.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibraryNext.d.ts","sourceRoot":"","sources":["../src/ExpoMediaLibraryNext.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAuB,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,OAAO,0BAA2B,SAAQ,YAAY,CAAC;IAC5D,qBAAqB,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,CAAC;CACvE,CAAC;IACA,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,KAAK,EAAE,OAAO,KAAK,CAAC;IAEpB,mBAAmB,CACjB,SAAS,CAAC,EAAE,OAAO,EACnB,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;IAC9B,uBAAuB,CACrB,SAAS,CAAC,EAAE,OAAO,EACnB,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;IAC9B,wBAAwB,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CACxE;;AAED,wBAAuF"} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibraryNext.js b/packages/expo-media-library/build/ExpoMediaLibraryNext.js deleted file mode 100644 index f3aec015bd2932..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibraryNext.js +++ /dev/null @@ -1,6 +0,0 @@ -import { NativeModule, requireNativeModule } from 'expo-modules-core'; -import { Album } from './types/Album'; -import { Asset } from './types/Asset'; -import { Query } from './types/Query'; -export default requireNativeModule('ExpoMediaLibraryNext'); -//# sourceMappingURL=ExpoMediaLibraryNext.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibraryNext.js.map b/packages/expo-media-library/build/ExpoMediaLibraryNext.js.map deleted file mode 100644 index b657be0d367daf..00000000000000 --- a/packages/expo-media-library/build/ExpoMediaLibraryNext.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"ExpoMediaLibraryNext.js","sourceRoot":"","sources":["../src/ExpoMediaLibraryNext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGtE,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAoBtC,eAAe,mBAAmB,CAA6B,sBAAsB,CAAC,CAAC","sourcesContent":["import type { PermissionResponse } from 'expo';\nimport { NativeModule, requireNativeModule } from 'expo-modules-core';\n\nimport type { GranularPermission, MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types';\nimport { Album } from './types/Album';\nimport { Asset } from './types/Asset';\nimport type { MediaTypeFilter } from './types/MediaTypeFilter';\nimport { Query } from './types/Query';\n\ndeclare class ExpoMediaLibraryNextModule extends NativeModule<{\n mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void;\n}> {\n Asset: typeof Asset;\n Album: typeof Album;\n Query: typeof Query;\n\n getPermissionsAsync(\n writeOnly?: boolean,\n granularPermissions?: GranularPermission[]\n ): Promise;\n requestPermissionsAsync(\n writeOnly?: boolean,\n granularPermissions?: GranularPermission[]\n ): Promise;\n presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise;\n}\n\nexport default requireNativeModule('ExpoMediaLibraryNext');\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibrary.d.ts b/packages/expo-media-library/build/MediaLibrary.d.ts index 6329d99a00ae98..3c523a6c75dcc2 100644 --- a/packages/expo-media-library/build/MediaLibrary.d.ts +++ b/packages/expo-media-library/build/MediaLibrary.d.ts @@ -1,2 +1,7 @@ +/** + * @hidden + * Temporary compatibility barrel for older internal imports. + * Prefer importing public APIs from the package root. + */ export * from './index'; //# sourceMappingURL=MediaLibrary.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibrary.d.ts.map b/packages/expo-media-library/build/MediaLibrary.d.ts.map index 98af76c2950daf..ac7cffcb958224 100644 --- a/packages/expo-media-library/build/MediaLibrary.d.ts.map +++ b/packages/expo-media-library/build/MediaLibrary.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"MediaLibrary.d.ts","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"} \ No newline at end of file +{"version":3,"file":"MediaLibrary.d.ts","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibrary.js b/packages/expo-media-library/build/MediaLibrary.js index f13cf5178e89b3..dc6f199f9c6251 100644 --- a/packages/expo-media-library/build/MediaLibrary.js +++ b/packages/expo-media-library/build/MediaLibrary.js @@ -1,2 +1,7 @@ +/** + * @hidden + * Temporary compatibility barrel for older internal imports. + * Prefer importing public APIs from the package root. + */ export * from './index'; //# sourceMappingURL=MediaLibrary.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibrary.js.map b/packages/expo-media-library/build/MediaLibrary.js.map index 9be5f386bdd1a8..6cb8b3944ca27c 100644 --- a/packages/expo-media-library/build/MediaLibrary.js.map +++ b/packages/expo-media-library/build/MediaLibrary.js.map @@ -1 +1 @@ -{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC","sourcesContent":["export * from './index';\n"]} \ No newline at end of file +{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../src/MediaLibrary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,cAAc,SAAS,CAAC","sourcesContent":["/**\n * @hidden\n * Temporary compatibility barrel for older internal imports.\n * Prefer importing public APIs from the package root.\n */\nexport * from './index';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibraryNext.types.d.ts b/packages/expo-media-library/build/MediaLibraryNext.types.d.ts deleted file mode 100644 index 02620cc17275d0..00000000000000 --- a/packages/expo-media-library/build/MediaLibraryNext.types.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from './types/SortDescriptor'; -export * from './types/AssetField'; -export * from './types/MediaSubtype'; -export * from './types/MediaType'; -export * from './types/MediaTypeFilter'; -export * from './types/GranularPermission'; -export * from './types/AssetInfo'; -export * from './types/AssetMetadata'; -export * from './types/Location'; -export * from './types/MediaLibraryAssetsChangeEvent'; -export * from './types/Shape'; -//# sourceMappingURL=MediaLibraryNext.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibraryNext.types.d.ts.map b/packages/expo-media-library/build/MediaLibraryNext.types.d.ts.map deleted file mode 100644 index dcbf76b3229295..00000000000000 --- a/packages/expo-media-library/build/MediaLibraryNext.types.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaLibraryNext.types.d.ts","sourceRoot":"","sources":["../src/MediaLibraryNext.types.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uCAAuC,CAAC;AACtD,cAAc,eAAe,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibraryNext.types.js b/packages/expo-media-library/build/MediaLibraryNext.types.js deleted file mode 100644 index a96556df6d6f39..00000000000000 --- a/packages/expo-media-library/build/MediaLibraryNext.types.js +++ /dev/null @@ -1,12 +0,0 @@ -export * from './types/SortDescriptor'; -export * from './types/AssetField'; -export * from './types/MediaSubtype'; -export * from './types/MediaType'; -export * from './types/MediaTypeFilter'; -export * from './types/GranularPermission'; -export * from './types/AssetInfo'; -export * from './types/AssetMetadata'; -export * from './types/Location'; -export * from './types/MediaLibraryAssetsChangeEvent'; -export * from './types/Shape'; -//# sourceMappingURL=MediaLibraryNext.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/MediaLibraryNext.types.js.map b/packages/expo-media-library/build/MediaLibraryNext.types.js.map deleted file mode 100644 index 1afaeddd15fa36..00000000000000 --- a/packages/expo-media-library/build/MediaLibraryNext.types.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaLibraryNext.types.js","sourceRoot":"","sources":["../src/MediaLibraryNext.types.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uCAAuC,CAAC;AACtD,cAAc,eAAe,CAAC","sourcesContent":["export * from './types/SortDescriptor';\nexport * from './types/AssetField';\nexport * from './types/MediaSubtype';\nexport * from './types/MediaType';\nexport * from './types/MediaTypeFilter';\nexport * from './types/GranularPermission';\nexport * from './types/AssetInfo';\nexport * from './types/AssetMetadata';\nexport * from './types/Location';\nexport * from './types/MediaLibraryAssetsChangeEvent';\nexport * from './types/Shape';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/index.d.ts b/packages/expo-media-library/build/index.d.ts index 91a4a6f61aadad..dba1cd9336f7b4 100644 --- a/packages/expo-media-library/build/index.d.ts +++ b/packages/expo-media-library/build/index.d.ts @@ -1,84 +1,3 @@ -import { type PermissionResponse } from 'expo'; -import { type EventSubscription } from 'expo-modules-core'; -import ExpoMediaLibraryNext from './ExpoMediaLibraryNext'; -import type { MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types'; -import type { GranularPermission } from './types/GranularPermission'; -import { MediaSubtype } from './types/MediaSubtype'; -import type { MediaTypeFilter } from './types/MediaTypeFilter'; -export * from './MediaLibraryNext.types'; -export declare class Query extends ExpoMediaLibraryNext.Query { -} -export declare class Asset extends ExpoMediaLibraryNext.Asset { - getMediaSubtypes(): Promise; - getLivePhotoVideoUri(): Promise; - getIsInCloud(): Promise; - getOrientation(): Promise; -} -export declare class Album extends ExpoMediaLibraryNext.Album { -} -/** - * Asks the user to grant permissions for accessing media in user's media library. - * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an - * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * - * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export declare function requestPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; -/** - * Checks user's permissions for accessing media library. - * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has - * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export declare function getPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; -/** - * Check or request permissions to access the media library. - * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. - * - * @example - * ```ts - * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ - * writeOnly: true, - * granularPermissions: ['photo'], - * }); - * ``` - */ -export declare const usePermissions: (options?: import("expo-modules-core").PermissionHookOptions<{ - writeOnly?: boolean; - granularPermissions?: GranularPermission[]; -}> | undefined) => [PermissionResponse | null, () => Promise, () => Promise]; -export { PermissionStatus, type PermissionHookOptions, type PermissionResponse } from 'expo'; -export type { EventSubscription } from 'expo-modules-core'; -/** - * Allows the user to update the assets that your app has access to. - * The system modal is only displayed if the user originally allowed only `limited` access to their - * media library, otherwise this method is a no-op. - * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. - * - * @return A promise that either rejects if the method is unavailable, or resolves to `void`. - * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. - * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). - * If `hasIncrementalChanges` is `false`, the user changed their permissions. - * - * @platform android 14+ - * @platform ios - */ -export declare function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; -/** - * Subscribes for updates in user's media library. - * @param listener A callback that is fired when any assets have been inserted or deleted from the - * library. On Android it's invoked with an empty object. On iOS it's invoked with - * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. - * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when - * you would like to unsubscribe the listener. - */ -export declare function addListener(listener: (event: MediaLibraryAssetsChangeEvent) => void): EventSubscription; -/** - * Removes all listeners. - */ -export declare function removeAllListeners(): void; +export * from './next'; export * from './legacyWarnings'; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/index.d.ts.map b/packages/expo-media-library/build/index.d.ts.map index 06297bdaf4a6b0..680bbfdb26e6fb 100644 --- a/packages/expo-media-library/build/index.d.ts.map +++ b/packages/expo-media-library/build/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,MAAM,CAAC;AACrE,OAAO,EAAuB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGhF,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,cAAc,0BAA0B,CAAC;AAEzC,qBAAa,KAAM,SAAQ,oBAAoB,CAAC,KAAK;CAAG;AAExD,qBAAa,KAAM,SAAQ,oBAAoB,CAAC,KAAK;IAEnD,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAQ3C,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW9C,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAQhC,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAMzC;AAED,qBAAa,KAAM,SAAQ,oBAAoB,CAAC,KAAK;CAAG;AAExD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,GAAE,OAAe,EAC1B,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,GAAE,OAAe,EAC1B,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;gBAEX,OAAO;0BAAwB,kBAAkB,EAAE;oHAKjE,CAAC;AAEH,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,KAAK,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAC7F,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,GACvD,iBAAiB,CAEnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,cAAc,kBAAkB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/index.js b/packages/expo-media-library/build/index.js index c0b37f55111ea3..47a7a583dfc080 100644 --- a/packages/expo-media-library/build/index.js +++ b/packages/expo-media-library/build/index.js @@ -1,127 +1,3 @@ -import { createPermissionHook } from 'expo'; -import { UnavailabilityError } from 'expo-modules-core'; -import { Platform } from 'react-native'; -import ExpoMediaLibraryNext from './ExpoMediaLibraryNext'; -import { MediaSubtype } from './types/MediaSubtype'; -export * from './MediaLibraryNext.types'; -export class Query extends ExpoMediaLibraryNext.Query { -} -export class Asset extends ExpoMediaLibraryNext.Asset { - // @hidden - getMediaSubtypes() { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS'); - } - return super.getMediaSubtypes(); - } - // @hidden - getLivePhotoVideoUri() { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getLivePhotoVideoUri is only available on iOS'); - } - return super.getLivePhotoVideoUri(); - } - // @hidden - getIsInCloud() { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS'); - } - return super.getIsInCloud(); - } - // @hidden - getOrientation() { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS'); - } - return super.getOrientation(); - } -} -export class Album extends ExpoMediaLibraryNext.Album { -} -/** - * Asks the user to grant permissions for accessing media in user's media library. - * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an - * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * - * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export async function requestPermissionsAsync(writeOnly = false, granularPermissions) { - if (!ExpoMediaLibraryNext.requestPermissionsAsync) { - throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync'); - } - if (Platform.OS === 'android') { - return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly, granularPermissions); - } - return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly); -} -/** - * Checks user's permissions for accessing media library. - * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has - * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export async function getPermissionsAsync(writeOnly = false, granularPermissions) { - if (!ExpoMediaLibraryNext.getPermissionsAsync) { - throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync'); - } - if (Platform.OS === 'android') { - return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly, granularPermissions); - } - return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly); -} -/** - * Check or request permissions to access the media library. - * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. - * - * @example - * ```ts - * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ - * writeOnly: true, - * granularPermissions: ['photo'], - * }); - * ``` - */ -export const usePermissions = createPermissionHook({ - getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions), - requestMethod: (options) => requestPermissionsAsync(options?.writeOnly, options?.granularPermissions), -}); -export { PermissionStatus } from 'expo'; -/** - * Allows the user to update the assets that your app has access to. - * The system modal is only displayed if the user originally allowed only `limited` access to their - * media library, otherwise this method is a no-op. - * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. - * - * @return A promise that either rejects if the method is unavailable, or resolves to `void`. - * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. - * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). - * If `hasIncrementalChanges` is `false`, the user changed their permissions. - * - * @platform android 14+ - * @platform ios - */ -export async function presentPermissionsPicker(mediaTypes) { - return await ExpoMediaLibraryNext.presentPermissionsPicker(mediaTypes); -} -/** - * Subscribes for updates in user's media library. - * @param listener A callback that is fired when any assets have been inserted or deleted from the - * library. On Android it's invoked with an empty object. On iOS it's invoked with - * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. - * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when - * you would like to unsubscribe the listener. - */ -export function addListener(listener) { - return ExpoMediaLibraryNext.addListener('mediaLibraryDidChange', listener); -} -/** - * Removes all listeners. - */ -export function removeAllListeners() { - ExpoMediaLibraryNext.removeAllListeners('mediaLibraryDidChange'); -} +export * from './next'; export * from './legacyWarnings'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/index.js.map b/packages/expo-media-library/build/index.js.map index 8d17a6b9720a20..677963c190b990 100644 --- a/packages/expo-media-library/build/index.js.map +++ b/packages/expo-media-library/build/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAA2B,MAAM,MAAM,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,oBAAoB,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGpD,cAAc,0BAA0B,CAAC;AAEzC,MAAM,OAAO,KAAM,SAAQ,oBAAoB,CAAC,KAAK;CAAG;AAExD,MAAM,OAAO,KAAM,SAAQ,oBAAoB,CAAC,KAAK;IACnD,UAAU;IACV,gBAAgB;QACd,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,2CAA2C,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAClC,CAAC;IAED,UAAU;IACV,oBAAoB;QAClB,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAC3B,cAAc,EACd,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,OAAO,KAAK,CAAC,oBAAoB,EAAE,CAAC;IACtC,CAAC;IAED,UAAU;IACV,YAAY;QACV,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uCAAuC,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,KAAK,CAAC,YAAY,EAAE,CAAC;IAC9B,CAAC;IAED,UAAU;IACV,cAAc;QACZ,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yCAAyC,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,KAAK,CAAC,cAAc,EAAE,CAAC;IAChC,CAAC;CACF;AAED,MAAM,OAAO,KAAM,SAAQ,oBAAoB,CAAC,KAAK;CAAG;AAExD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,oBAAoB,CAAC,uBAAuB,EAAE,CAAC;QAClD,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,oBAAoB,CAAC,uBAAuB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,MAAM,oBAAoB,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;AACvE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,oBAAoB,CAAC,mBAAmB,EAAE,CAAC;QAC9C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,oBAAoB,CAAC,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,MAAM,oBAAoB,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAGhD;IACA,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;IAC7F,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CACzB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;CAC5E,CAAC,CAAC;AAEH,OAAO,EAAE,gBAAgB,EAAuD,MAAM,MAAM,CAAC;AAG7F;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,UAA8B;IAC3E,OAAO,MAAM,oBAAoB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,QAAwD;IAExD,OAAO,oBAAoB,CAAC,WAAW,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,oBAAoB,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;AACnE,CAAC;AAED,cAAc,kBAAkB,CAAC","sourcesContent":["import { createPermissionHook, type PermissionResponse } from 'expo';\nimport { UnavailabilityError, type EventSubscription } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport ExpoMediaLibraryNext from './ExpoMediaLibraryNext';\nimport type { MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types';\nimport type { GranularPermission } from './types/GranularPermission';\nimport { MediaSubtype } from './types/MediaSubtype';\nimport type { MediaTypeFilter } from './types/MediaTypeFilter';\n\nexport * from './MediaLibraryNext.types';\n\nexport class Query extends ExpoMediaLibraryNext.Query {}\n\nexport class Asset extends ExpoMediaLibraryNext.Asset {\n // @hidden\n getMediaSubtypes(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS');\n }\n return super.getMediaSubtypes();\n }\n\n // @hidden\n getLivePhotoVideoUri(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError(\n 'MediaLibrary',\n 'getLivePhotoVideoUri is only available on iOS'\n );\n }\n return super.getLivePhotoVideoUri();\n }\n\n // @hidden\n getIsInCloud(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS');\n }\n return super.getIsInCloud();\n }\n\n // @hidden\n getOrientation(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS');\n }\n return super.getOrientation();\n }\n}\n\nexport class Album extends ExpoMediaLibraryNext.Album {}\n\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`.\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n *\n * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!ExpoMediaLibraryNext.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly);\n}\n\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`.\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!ExpoMediaLibraryNext.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly);\n}\n\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n * writeOnly: true,\n * granularPermissions: ['photo'],\n * });\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\nexport { PermissionStatus, type PermissionHookOptions, type PermissionResponse } from 'expo';\nexport type { EventSubscription } from 'expo-modules-core';\n\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise {\n return await ExpoMediaLibraryNext.presentPermissionsPicker(mediaTypes);\n}\n\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS it's invoked with\n * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object.\n * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when\n * you would like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return ExpoMediaLibraryNext.addListener('mediaLibraryDidChange', listener);\n}\n\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n ExpoMediaLibraryNext.removeAllListeners('mediaLibraryDidChange');\n}\n\nexport * from './legacyWarnings';\n"]} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,kBAAkB,CAAC","sourcesContent":["export * from './next';\nexport * from './legacyWarnings';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.d.ts b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.d.ts similarity index 100% rename from packages/expo-media-library/build/ExpoMediaLibrary.d.ts rename to packages/expo-media-library/build/legacy/ExpoMediaLibrary.d.ts diff --git a/packages/expo-media-library/build/legacy/ExpoMediaLibrary.d.ts.map b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.d.ts.map new file mode 100644 index 00000000000000..19422c697c516a --- /dev/null +++ b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ExpoMediaLibrary.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoMediaLibrary.ts"],"names":[],"mappings":";AACA,wBAAuD"} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.js b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.js similarity index 100% rename from packages/expo-media-library/build/ExpoMediaLibrary.js rename to packages/expo-media-library/build/legacy/ExpoMediaLibrary.js diff --git a/packages/expo-media-library/build/legacy/ExpoMediaLibrary.js.map b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.js.map new file mode 100644 index 00000000000000..c8937804456744 --- /dev/null +++ b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ExpoMediaLibrary.js","sourceRoot":"","sources":["../../src/legacy/ExpoMediaLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,eAAe,mBAAmB,CAAC,kBAAkB,CAAC,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\nexport default requireNativeModule('ExpoMediaLibrary');\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts similarity index 84% rename from packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts rename to packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts index 2d24c344da8dde..44527ec2425a55 100644 --- a/packages/expo-media-library/build/ExpoMediaLibrary.web.d.ts +++ b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts @@ -1,5 +1,5 @@ import { type PermissionResponse } from 'expo'; -import type { MediaTypeObject, SortByObject } from './legacy/MediaLibrary'; +import type { MediaTypeObject, SortByObject } from './MediaLibrary'; declare const _default: { readonly CHANGE_LISTENER_NAME: string; readonly MediaType: MediaTypeObject; diff --git a/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts.map b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts.map new file mode 100644 index 00000000000000..ef56b2d00fa1aa --- /dev/null +++ b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ExpoMediaLibrary.web.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoMediaLibrary.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAoB,MAAM,MAAM,CAAC;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;;mCAUtC,MAAM;wBAGjB,eAAe;qBAQlB,YAAY;oCAYY,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;wCAGjC,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;;AA3BjF,wBA8BE"} \ No newline at end of file diff --git a/packages/expo-media-library/build/ExpoMediaLibrary.web.js b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.js similarity index 100% rename from packages/expo-media-library/build/ExpoMediaLibrary.web.js rename to packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.js diff --git a/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.js.map b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.js.map new file mode 100644 index 00000000000000..2c83e64019a466 --- /dev/null +++ b/packages/expo-media-library/build/legacy/ExpoMediaLibrary.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"ExpoMediaLibrary.web.js","sourceRoot":"","sources":["../../src/legacy/ExpoMediaLibrary.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,gBAAgB,EAAE,MAAM,MAAM,CAAC;AAIjE,MAAM,oBAAoB,GAAuB;IAC/C,MAAM,EAAE,gBAAgB,CAAC,YAAY;IACrC,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF,eAAe;IACb,IAAI,oBAAoB;QACtB,OAAO,uBAAuB,CAAC;IACjC,CAAC;IACD,IAAI,SAAS;QACX,OAAO;YACL,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,OAAO;YACd,OAAO,EAAE,SAAS;SACnB,CAAC;IACJ,CAAC;IACD,IAAI,MAAM;QACR,OAAO;YACL,OAAO,EAAE,SAAS;YAClB,SAAS,EAAE,WAAW;YACtB,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,QAAQ;YAChB,YAAY,EAAE,cAAc;YAC5B,gBAAgB,EAAE,kBAAkB;YACpC,QAAQ,EAAE,UAAU;SACrB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,UAAmB;QAC3C,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,uBAAuB,CAAC,UAAmB;QAC/C,OAAO,oBAAoB,CAAC;IAC9B,CAAC;CACF,CAAC","sourcesContent":["import { type PermissionResponse, PermissionStatus } from 'expo';\n\nimport type { MediaTypeObject, SortByObject } from './MediaLibrary';\n\nconst noPermissionResponse: PermissionResponse = {\n status: PermissionStatus.UNDETERMINED,\n canAskAgain: true,\n granted: false,\n expires: 'never',\n};\n\nexport default {\n get CHANGE_LISTENER_NAME(): string {\n return 'mediaLibraryDidChange';\n },\n get MediaType(): MediaTypeObject {\n return {\n audio: 'audio',\n photo: 'photo',\n video: 'video',\n unknown: 'unknown',\n };\n },\n get SortBy(): SortByObject {\n return {\n default: 'default',\n mediaType: 'mediaType',\n width: 'width',\n height: 'height',\n creationTime: 'creationTime',\n modificationTime: 'modificationTime',\n duration: 'duration',\n };\n },\n\n async getPermissionsAsync(_writeOnly: boolean): Promise {\n return noPermissionResponse;\n },\n async requestPermissionsAsync(_writeOnly: boolean): Promise {\n return noPermissionResponse;\n },\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/legacy/MediaLibrary.js b/packages/expo-media-library/build/legacy/MediaLibrary.js index 21d4c8e09426f6..eeb828730d443e 100644 --- a/packages/expo-media-library/build/legacy/MediaLibrary.js +++ b/packages/expo-media-library/build/legacy/MediaLibrary.js @@ -1,7 +1,7 @@ import { createPermissionHook } from 'expo'; import { UnavailabilityError } from 'expo-modules-core'; import { Platform } from 'react-native'; -import MediaLibrary from '../ExpoMediaLibrary'; +import MediaLibrary from './ExpoMediaLibrary'; const isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo; let loggedExpoGoWarning = false; if (isExpoGo && !loggedExpoGoWarning) { diff --git a/packages/expo-media-library/build/legacy/MediaLibrary.js.map b/packages/expo-media-library/build/legacy/MediaLibrary.js.map index eb77823161da87..1d55c7b220c8c0 100644 --- a/packages/expo-media-library/build/legacy/MediaLibrary.js.map +++ b/packages/expo-media-library/build/legacy/MediaLibrary.js.map @@ -1 +1 @@ -{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../../src/legacy/MediaLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmD,oBAAoB,EAAE,MAAM,MAAM,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAE/C,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,WAAW,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;AAEjF,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC,IAAI,QAAQ,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACrC,OAAO,CAAC,IAAI,CACV,wQAAwQ,CACzQ,CAAC;IACF,mBAAmB,GAAG,IAAI,CAAC;AAC7B,CAAC;AA0VD,4CAA4C;AAC5C,OAAO,EACL,gBAAgB,GAIjB,MAAM,MAAM,CAAC;AACd,OAAO,EAA0C,MAAM,mBAAmB,CAAC;AAE3E,SAAS,QAAQ,CAAI,IAAa;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,KAAK,CAAC,GAAyC;IACtD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,QAAmB;IACxC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAmB;IACxC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,SAAkB;IACxC,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,SAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAe;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAW;IACjC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,MAA+B;IAC3D,WAAW,CAAC,MAAM,CAAC,CAAC;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,CAAC;IACD,OAAO,GAAG,MAAM,OAAO,CAAC;AAC1B,CAAC;AAED,SAAS,YAAY,CAAC,KAAqB;IACzC,OAAO,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAED,cAAc;AACd;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAoB,YAAY,CAAC,SAAS,CAAC;AAEjE,cAAc;AACd;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAiB,YAAY,CAAC,MAAM,CAAC;AAExD,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,CAAC,CAAC,YAAY,IAAI,gBAAgB,IAAI,YAAY,CAAC;AAC5D,CAAC;AAED,2BAA2B;AAC3B;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,YAAY,CAAC,uBAAuB,EAAE,CAAC;QAC1C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAC/D,CAAC;AAED,2BAA2B;AAC3B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAGhD;IACA,4FAA4F;IAC5F,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;IAC7F,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CACzB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;CAC5E,CAAC,CAAC;AAEH,cAAc;AACd;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,aAAgC,CAAC,OAAO,EAAE,OAAO,CAAC;IAElD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,mBAAmB,CAC3B,cAAc,EACd,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACxD,MAAM,YAAY,CAAC,uBAAuB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,6BAA6B,EAAE,CAAC;QAChD,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,+BAA+B,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,6BAA6B,EAAE,CAAC;AAC5D,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,KAAgB;IACvE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAErE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,sEAAsE;QACtE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,oBAAoB,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAA6B,EAC7B,KAAe,EACf,OAAgB,IAAI;IAEpB,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,QAAQ,CAAC,CAAC;IAExB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAA6B,EAC7B,KAAe;IAEf,IAAI,CAAC,YAAY,CAAC,0BAA0B,EAAE,CAAC;QAC7C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,MAAM,YAAY,CAAC,0BAA0B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAA6B;IACnE,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE7C,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAe,EACf,UAA6C,EAAE,yBAAyB,EAAE,IAAI,EAAE;IAEhF,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzB,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAEzE,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,2EAA2E;QAC3E,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAE,kBAAkB,GAAG,KAAK,KAAoB,EAAE;IAGrF,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC;QAChC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,KAAgB,EAChB,YAAqB,IAAI,EACzB,oBAA6B;IAE7B,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,IACE,QAAQ,CAAC,EAAE,KAAK,SAAS;QACzB,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACrD,CAAC,oBAAoB,EACrB,CAAC;QACD,wFAAwF;QACxF,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,MAAM,YAAY,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AACpG,CAAC;AAED,cAAc;AACd;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA6B,EAC7B,cAAuB,KAAK;IAE5B,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE7C,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,gBAA+B,EAAE;IACpE,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,mBAAmB,GACpB,GAAG,aAAa,CAAC;IAElB,MAAM,OAAO,GAAG;QACd,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;QACjC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;QACxB,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnD,aAAa,EAAE,QAAQ,CAAC,aAAa,CAAC;QACtC,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC;QACxC,aAAa,EAAE,YAAY,CAAC,aAAa,CAAC;QAC1C,mBAAmB,EAAE,mBAAmB,IAAI,KAAK;KAClD,CAAC;IAEF,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1C,8DAA8D;IAC9D,OAAO,MAAM,YAAY,CAAC,cAAc,CAAC;QACvC,GAAG,OAAO;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC;KACjD,CAAC,CAAC;AACL,CAAC;AAED,cAAc;AACd;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,QAAwD;IAExD,OAAO,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED;GACG;AACH,MAAM,UAAU,kBAAkB,CAAC,YAA+B;IAChE,YAAY,CAAC,MAAM,EAAE,CAAC;AACxB,CAAC;AAED,cAAc;AACd;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,YAAY,CAAC,kBAAkB,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC;AACrE,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,eAAe,EAAE,CAAC;AAC9C,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAAe;IAC7D,IAAI,CAAC,YAAY,CAAC,yBAAyB,EAAE,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,yBAAyB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAe;IAC5D,IAAI,CAAC,YAAY,CAAC,wBAAwB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAe,EACf,UAAmB;IAEnB,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gDAAgD,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzB,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import { type PermissionResponse as EXPermissionResponse, createPermissionHook } from 'expo';\nimport { UnavailabilityError, type EventSubscription } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport MediaLibrary from '../ExpoMediaLibrary';\n\nconst isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo;\n\nlet loggedExpoGoWarning = false;\n\nif (isExpoGo && !loggedExpoGoWarning) {\n console.warn(\n 'Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build. https://docs.expo.dev/develop/development-builds/create-a-build'\n );\n loggedExpoGoWarning = true;\n}\n\n// @needsAudit\nexport type PermissionResponse = EXPermissionResponse & {\n /**\n * Indicates if your app has access to the whole or only part of the photo library. Possible values are:\n * - `'all'` if the user granted your app access to the whole photo library\n * - `'limited'` if the user granted your app access only to selected photos (only available on Android API 14+ and iOS 14.0+)\n * - `'none'` if user denied or hasn't yet granted the permission\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n/**\n * Determines the type of media that the app will ask the OS to get access to.\n * @platform android 13+\n */\nexport type GranularPermission = 'audio' | 'photo' | 'video';\n\nexport type MediaTypeValue = 'audio' | 'photo' | 'video' | 'unknown' | 'pairedVideo';\n\n/**\n * Represents the possible types of media that the app will ask the OS to get access to when calling [`presentPermissionsPickerAsync()`](#medialibrarypresentpermissionspickerasyncmediatypes).\n * @platform android 14+\n * */\nexport type MediaTypeFilter = 'photo' | 'video';\n\nexport type SortByKey =\n | 'default'\n | 'mediaType'\n | 'width'\n | 'height'\n | 'creationTime'\n | 'modificationTime'\n | 'duration';\nexport type SortByValue = [SortByKey, boolean] | SortByKey;\n\ntype InternalSortByValue = `${SortByKey} ${'ASC' | 'DESC'}`;\n\nexport type MediaTypeObject = {\n audio: 'audio';\n photo: 'photo';\n video: 'video';\n unknown: 'unknown';\n};\n\nexport type SortByObject = {\n default: 'default';\n mediaType: 'mediaType';\n width: 'width';\n height: 'height';\n creationTime: 'creationTime';\n modificationTime: 'modificationTime';\n duration: 'duration';\n};\n\n// @needsAudit\nexport type Asset = {\n /**\n * Internal ID that represents an asset.\n */\n id: string;\n /**\n * Filename of the asset.\n */\n filename: string;\n /**\n * URI that points to the asset. `ph://*` (iOS), `file://*` (Android)\n */\n uri: string;\n /**\n * Media type.\n */\n mediaType: MediaTypeValue;\n /**\n * An array of media subtypes.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[];\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * File creation timestamp.\n */\n creationTime: number;\n /**\n * Last modification timestamp.\n */\n modificationTime: number;\n /**\n * Duration of the video or audio asset in seconds.\n */\n duration: number;\n /**\n * Album ID that the asset belongs to.\n * @platform android\n */\n albumId?: string;\n};\n\n// @needsAudit\nexport type AssetInfo = Asset & {\n /**\n * Local URI for the asset.\n */\n localUri?: string;\n /**\n * GPS location if available.\n */\n location?: Location;\n /**\n * EXIF metadata associated with the image.\n */\n exif?: object;\n /**\n * Whether the asset is marked as favorite.\n * @platform ios\n */\n isFavorite?: boolean;\n /**\n * This field is available only if flag `shouldDownloadFromNetwork` is set to `false`.\n * Whether the asset is stored on the network (iCloud on iOS).\n * @platform ios\n */\n isNetworkAsset?: boolean; //iOS only\n /**\n * Display orientation of the image. Orientation is available only for assets whose\n * `mediaType` is `MediaType.photo`. Value will range from 1 to 8, see [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html)\n * for more details.\n * @platform ios\n */\n orientation?: number;\n /**\n * Contains information about the video paired with the image file.\n * This field is available if the `mediaType` is `\"photo\"`, and the `mediaSubtypes` includes `\"livePhoto\"`.\n * @platform ios\n */\n pairedVideoAsset?: Asset | null;\n};\n\n/**\n * Constants identifying specific variations of asset media, such as panorama or screenshot photos,\n * and time-lapse or high-frame-rate video. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype#1603888).\n * @platform ios\n * */\nexport type MediaSubtype =\n | 'depthEffect'\n | 'hdr'\n | 'highFrameRate'\n | 'livePhoto'\n | 'panorama'\n | 'screenshot'\n | 'stream'\n | 'timelapse'\n | 'spatialMedia'\n | 'videoCinematic';\n\n// @needsAudit\nexport type MediaLibraryAssetInfoQueryOptions = {\n /**\n * Whether allow the asset to be downloaded from network. Only available in iOS with iCloud assets.\n * @default true\n */\n shouldDownloadFromNetwork?: boolean;\n};\n\n// @needsAudit\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes could be described as \"incremental changes\".\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload (eg. a user has changed access to individual assets in the\n * media library).\n */\n hasIncrementalChanges: boolean;\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been inserted to the library.\n */\n insertedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been deleted from the library.\n */\n deletedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been updated or completed downloading from network\n * storage (iCloud on iOS).\n */\n updatedAssets?: Asset[];\n};\n\n// @docsMissing\nexport type Location = {\n latitude: number;\n longitude: number;\n};\n\n// @needsAudit\nexport type Album = {\n /**\n * Album ID.\n */\n id: string;\n /**\n * Album title.\n */\n title: string;\n /**\n * Estimated number of assets in album.\n */\n assetCount: number;\n /**\n * The type of the assets album.\n * @platform ios\n */\n type?: AlbumType;\n /**\n * Apply only to albums whose type is `'moment'`. Earliest creation timestamp of all\n * assets in moment.\n * @platform ios\n */\n startTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Latest creation timestamp of all\n * assets in moment.\n * @platform ios\n */\n endTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Approximated location of all\n * assets in moment.\n * @platform ios\n */\n approximateLocation?: Location;\n /**\n * Apply only to albums whose type is `'moment'`. Names of locations grouped\n * in moment.\n * @platform ios\n */\n locationNames?: string[];\n};\n\n// @docsMissing\nexport type AlbumType = 'album' | 'moment' | 'smartAlbum';\n\n// @docsMissing\nexport type AlbumsOptions = {\n includeSmartAlbums?: boolean;\n};\n\n// @needsAudit\nexport type AssetsOptions = {\n /**\n * The maximum number of items on a single page.\n * @default 20\n */\n first?: number;\n /**\n * Asset ID of the last item returned on the previous page. To get the ID of the next page,\n * pass [`endCursor`](#pagedinfo) as its value.\n */\n after?: AssetRef;\n /**\n * [Album](#album) or its ID to get assets from specific album.\n */\n album?: AlbumRef;\n /**\n * An array of [`SortByValue`](#sortbyvalue)s or a single `SortByValue` value. By default, all\n * keys are sorted in descending order, however you can also pass a pair `[key, ascending]` where\n * the second item is a `boolean` value that means whether to use ascending order. Note that if\n * the `SortBy.default` key is used, then `ascending` argument will not matter. Earlier items have\n * higher priority when sorting out the results.\n * If empty, this method uses the default sorting that is provided by the platform.\n */\n sortBy?: SortByValue[] | SortByValue;\n /**\n * An array of [MediaTypeValue](#mediatypevalue)s or a single `MediaTypeValue`.\n * @default MediaType.photo\n */\n mediaType?: MediaTypeValue[] | MediaTypeValue;\n /**\n * An array of [MediaSubtype](#mediasubtype)s or a single `MediaSubtype`.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[] | MediaSubtype;\n /**\n * `Date` object or Unix timestamp in milliseconds limiting returned assets only to those that\n * were created after this date.\n */\n createdAfter?: Date | number;\n /**\n * Similarly as `createdAfter`, but limits assets only to those that were created before specified\n * date.\n */\n createdBefore?: Date | number;\n /**\n * Whether to resolve full info for the assets during the query.\n * This is useful to get the full EXIF data for images. It can fix the orientation of the image.\n * @default false\n * @platform android\n */\n resolveWithFullInfo?: boolean;\n};\n\n// @needsAudit\nexport type PagedInfo = {\n /**\n * A page of [`Asset`](#asset)s fetched by the query.\n */\n assets: T[];\n /**\n * A marker that indicates where the next page of results should start.\n * On iOS, it is the ID of the last fetched asset.\n * On Android, it is the index of the last fetched asset in query results.\n * This value should be passed as the `after` option to load the next page.\n */\n endCursor: string;\n /**\n * Whether there are more assets to fetch.\n */\n hasNextPage: boolean;\n /**\n * Estimated total number of assets that match the query.\n */\n totalCount: number;\n};\n\n/**\n * @hidden\n */\nexport type AssetRef = Asset | string;\n\n/**\n * @hidden\n */\nexport type AlbumRef = Album | string;\n\n// TODO(@kitten): Remove re-exports from EMC\nexport {\n PermissionStatus,\n type PermissionExpiration,\n type PermissionResponse as EXPermissionResponse,\n type PermissionHookOptions,\n} from 'expo';\nexport { type EventSubscription as Subscription } from 'expo-modules-core';\n\nfunction arrayize(item: T | T[]): T[] {\n if (Array.isArray(item)) {\n return item;\n }\n return item ? [item] : [];\n}\n\nfunction getId(ref: string | undefined | { id?: string }): string | undefined {\n if (typeof ref === 'string') {\n return ref;\n }\n return ref ? ref.id : undefined;\n}\n\nfunction checkAssetIds(assetIds: unknown[]): asserts assetIds is string[] {\n if (assetIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Asset ID must be a string!');\n }\n}\n\nfunction checkAlbumIds(albumIds: unknown[]): asserts albumIds is string[] {\n if (albumIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Album ID must be a string!');\n }\n}\n\nfunction checkMediaType(mediaType: unknown): asserts mediaType is keyof MediaTypeObject {\n if (Object.values(MediaType).indexOf(mediaType as any) === -1) {\n throw new Error(`Invalid mediaType: ${mediaType}`);\n }\n}\n\nfunction checkSortBy(sortBy: unknown): asserts sortBy is SortByValue {\n if (Array.isArray(sortBy)) {\n checkSortByKey(sortBy[0]);\n\n if (typeof sortBy[1] !== 'boolean') {\n throw new Error('Invalid sortBy array argument. Second item must be a boolean!');\n }\n } else {\n checkSortByKey(sortBy);\n }\n}\n\nfunction checkSortByKey(sortBy: any): void {\n if (Object.values(SortBy).indexOf(sortBy) === -1) {\n throw new Error(`Invalid sortBy key: ${sortBy}`);\n }\n}\n\nfunction sortByOptionToString(sortBy: SortByValue | undefined): InternalSortByValue {\n checkSortBy(sortBy);\n if (Array.isArray(sortBy)) {\n return `${sortBy[0]} ${sortBy[1] ? 'ASC' : 'DESC'}`;\n }\n return `${sortBy} DESC`;\n}\n\nfunction dateToNumber(value?: Date | number): number | undefined {\n return value instanceof Date ? value.getTime() : value;\n}\n\n// @needsAudit\n/**\n * Possible media types.\n */\nexport const MediaType: MediaTypeObject = MediaLibrary.MediaType;\n\n// @needsAudit\n/**\n * Supported keys that can be used to sort `getAssetsAsync` results.\n */\nexport const SortBy: SortByObject = MediaLibrary.SortBy;\n\n// @needsAudit\n/**\n * Returns whether the Media Library API is enabled on the current device.\n * @return A promise which fulfils with a `boolean`, indicating whether the Media Library API is\n * available on the current device.\n */\nexport async function isAvailableAsync(): Promise {\n return !!MediaLibrary && 'getAssetsAsync' in MediaLibrary;\n}\n\n// @needsAudit @docsMissing\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n *\n * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in plugin.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!MediaLibrary.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.requestPermissionsAsync(writeOnly);\n}\n\n// @needsAudit @docsMissing\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!MediaLibrary.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.getPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions();\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\n// @needsAudit\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPickerAsync(\n mediaTypes: MediaTypeFilter[] = ['photo', 'video']\n): Promise {\n if (Platform.OS === 'android' && isExpoGo) {\n throw new UnavailabilityError(\n 'MediaLibrary',\n 'presentPermissionsPickerAsync is unavailable in Expo Go'\n );\n }\n if (Platform.OS === 'android' && Platform.Version >= 34) {\n await MediaLibrary.requestPermissionsAsync(false, mediaTypes);\n return;\n }\n if (!MediaLibrary.presentPermissionsPickerAsync) {\n throw new UnavailabilityError('MediaLibrary', 'presentPermissionsPickerAsync');\n }\n return await MediaLibrary.presentPermissionsPickerAsync();\n}\n\n// @needsAudit\n/**\n * Creates an asset from existing file. The most common use case is to save a picture taken by [Camera](./camera).\n * This method requires `CAMERA_ROLL` permission.\n *\n * @example\n * ```js\n * const { uri } = await Camera.takePictureAsync();\n * const asset = await MediaLibrary.createAssetAsync(uri);\n * ```\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`\n *\n * @param album An [Album](#album) or its ID. If provided, the asset will be added to this album upon creation, otherwise it will be added to the default album for the media type.\n * The album has exist.\n * @return A promise which fulfils with an object representing an [`Asset`](#asset).\n */\nexport async function createAssetAsync(localUri: string, album?: AlbumRef): Promise {\n if (!MediaLibrary.createAssetAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAssetAsync');\n }\n\n const albumId = getId(album);\n\n if (!localUri || typeof localUri !== 'string') {\n throw new Error('Invalid argument \"localUri\". It must be a string!');\n }\n const asset = await MediaLibrary.createAssetAsync(localUri, albumId);\n\n if (Array.isArray(asset)) {\n // Android returns an array with asset, we need to pick the first item\n return asset[0];\n }\n return asset;\n}\n\n// @needsAudit\n/**\n * Saves the file at given `localUri` to the user's media library. Unlike `createAssetAsync()`,\n * This method doesn't return created asset.\n * On __iOS 11+__, it's possible to use this method without asking for `CAMERA_ROLL` permission,\n * however then yours `Info.plist` should have `NSPhotoLibraryAddUsageDescription` key.\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`.\n */\nexport async function saveToLibraryAsync(localUri: string): Promise {\n if (!MediaLibrary.saveToLibraryAsync) {\n throw new UnavailabilityError('MediaLibrary', 'saveToLibraryAsync');\n }\n return await MediaLibrary.saveToLibraryAsync(localUri);\n}\n\n// @needsAudit\n/**\n * Adds array of assets to the album.\n *\n * On Android, by default it copies assets from the current album to provided one, however it's also\n * possible to move them by passing `false` as `copyAssets` argument. In case they're copied you\n * should keep in mind that `getAssetsAsync` will return duplicated assets.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @param copy __Android only.__ Whether to copy assets to the new album instead of move them.\n * Defaults to `true`.\n * @return Returns promise which fulfils with `true` if the assets were successfully added to\n * the album.\n */\nexport async function addAssetsToAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef,\n copy: boolean = true\n): Promise {\n if (!MediaLibrary.addAssetsToAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'addAssetsToAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n\n if (!albumId || typeof albumId !== 'string') {\n throw new Error('Invalid album ID. It must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId);\n }\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId, !!copy);\n}\n\n// @needsAudit\n/**\n * Removes given assets from album.\n *\n * On Android, album will be automatically deleted if there are no more assets inside.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @return Returns promise which fulfils with `true` if the assets were successfully removed from\n * the album.\n */\nexport async function removeAssetsFromAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef\n): Promise {\n if (!MediaLibrary.removeAssetsFromAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'removeAssetsFromAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.removeAssetsFromAlbumAsync(assetIds, albumId);\n}\n\n// @needsAudit\n/**\n * Deletes assets from the library. On iOS it deletes assets from all albums they belong to, while\n * on Android it keeps all copies of them (album is strictly connected to the asset). Also, there is\n * additional dialog on iOS that requires user to confirm this action.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @return Returns promise which fulfils with `true` if the assets were successfully deleted.\n */\nexport async function deleteAssetsAsync(assets: AssetRef[] | AssetRef): Promise {\n if (!MediaLibrary.deleteAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAssetsAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.deleteAssetsAsync(assetIds);\n}\n\n// @needsAudit\n/**\n * Provides more information about an asset, including GPS location, local URI and EXIF metadata.\n * For better performance, prefer using individual getters such as `asset.getLocation()` or `asset.getExif()` to fetch only the data you need.\n * @param asset An [Asset](#asset) or its ID.\n * @param options\n * @return An [AssetInfo](#assetinfo) object, which is an `Asset` extended by an additional fields.\n */\nexport async function getAssetInfoAsync(\n asset: AssetRef,\n options: MediaLibraryAssetInfoQueryOptions = { shouldDownloadFromNetwork: true }\n): Promise {\n if (!MediaLibrary.getAssetInfoAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetInfoAsync');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n const assetInfo = await MediaLibrary.getAssetInfoAsync(assetId, options);\n\n if (Array.isArray(assetInfo)) {\n // Android returns an array with asset info, we need to pick the first item\n return assetInfo[0];\n }\n return assetInfo;\n}\n\n// @needsAudit\n/**\n * Queries for user-created albums in media gallery.\n * @return A promise which fulfils with an array of [`Album`](#asset)s. Depending on Android version,\n * root directory of your storage may be listed as album titled `\"0\"` or unlisted at all.\n */\nexport async function getAlbumsAsync({ includeSmartAlbums = false }: AlbumsOptions = {}): Promise<\n Album[]\n> {\n if (!MediaLibrary.getAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumsAsync');\n }\n return await MediaLibrary.getAlbumsAsync({ includeSmartAlbums });\n}\n\n// @needsAudit\n/**\n * Queries for an album with a specific name.\n * @param title Name of the album to look for.\n * @return An object representing an [`Album`](#album), if album with given name exists, otherwise\n * returns `null`.\n */\nexport async function getAlbumAsync(title: string): Promise {\n if (!MediaLibrary.getAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumAsync');\n }\n if (typeof title !== 'string') {\n throw new Error('Album title must be a string!');\n }\n return await MediaLibrary.getAlbumAsync(title);\n}\n\n// @needsAudit\n/**\n * Creates an album with given name and initial asset. The asset parameter is required on Android,\n * since it's not possible to create empty album on this platform. On Android, by default it copies\n * given asset from the current album to the new one, however it's also possible to move it by\n * passing `false` as `copyAsset` argument.\n * In case it's copied you should keep in mind that `getAssetsAsync` will return duplicated asset.\n * > On Android, it's not possible to create an empty album. You must provide an existing asset to copy or move into the album or an uri of a local file, which will be used to create an initial asset for the album.\n * @param albumName Name of the album to create.\n * @param asset An [Asset](#asset) or its ID. On Android you either need to provide an asset or a localUri.\n * @param initialAssetLocalUri A URI to the local media file, which will be used to create the initial asset inside the album. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`. If the `asset` was provided, this parameter will be ignored.\n * @param copyAsset __Android Only.__ Whether to copy asset to the new album instead of move it. This parameter is ignored if `asset` was not provided.\n * Defaults to `true`.\n * @return Newly created [`Album`](#album).\n */\nexport async function createAlbumAsync(\n albumName: string,\n asset?: AssetRef,\n copyAsset: boolean = true,\n initialAssetLocalUri?: string\n): Promise {\n if (!MediaLibrary.createAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAlbumAsync');\n }\n\n const assetId = getId(asset);\n\n if (\n Platform.OS === 'android' &&\n (typeof assetId !== 'string' || assetId.length === 0) &&\n !initialAssetLocalUri\n ) {\n // it's not possible to create empty album on Android, so initial asset must be provided\n throw new Error(\n 'MediaLibrary.createAlbumAsync must be called with an asset or a localUri on Android.'\n );\n }\n if (!albumName || typeof albumName !== 'string') {\n throw new Error('Invalid argument \"albumName\". It must be a string!');\n }\n if (assetId != null && typeof assetId !== 'string') {\n throw new Error('Asset ID must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.createAlbumAsync(albumName, assetId, initialAssetLocalUri);\n }\n return await MediaLibrary.createAlbumAsync(albumName, assetId, !!copyAsset, initialAssetLocalUri);\n}\n\n// @needsAudit\n/**\n * Deletes given albums from the library. On Android by default it deletes assets belonging to given\n * albums from the library. On iOS it doesn't delete these assets, however it's possible to do by\n * passing `true` as `deleteAssets`.\n * @param albums An array of [`Album`](#asset)s or their IDs.\n * @param assetRemove __iOS Only.__ Whether to also delete assets belonging to given albums.\n * Defaults to `false`.\n * @return Returns a promise which fulfils with `true` if the albums were successfully deleted from\n * the library.\n */\nexport async function deleteAlbumsAsync(\n albums: AlbumRef[] | AlbumRef,\n assetRemove: boolean = false\n): Promise {\n if (!MediaLibrary.deleteAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAlbumsAsync');\n }\n\n const albumIds = arrayize(albums).map(getId);\n\n checkAlbumIds(albumIds);\n if (Platform.OS === 'android') {\n return await MediaLibrary.deleteAlbumsAsync(albumIds);\n }\n return await MediaLibrary.deleteAlbumsAsync(albumIds, !!assetRemove);\n}\n\n// @needsAudit\n/**\n * Fetches a page of assets matching the provided criteria.\n * @param assetsOptions\n * @return A promise that fulfils with to [`PagedInfo`](#pagedinfo) object with array of [`Asset`](#asset)s.\n */\nexport async function getAssetsAsync(assetsOptions: AssetsOptions = {}): Promise> {\n if (!MediaLibrary.getAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetsAsync');\n }\n\n const {\n first,\n after,\n album,\n sortBy,\n mediaType,\n createdAfter,\n createdBefore,\n mediaSubtypes,\n resolveWithFullInfo,\n } = assetsOptions;\n\n const options = {\n first: first == null ? 20 : first,\n after: getId(after),\n album: getId(album),\n sortBy: arrayize(sortBy),\n mediaType: arrayize(mediaType || [MediaType.photo]),\n mediaSubtypes: arrayize(mediaSubtypes),\n createdAfter: dateToNumber(createdAfter),\n createdBefore: dateToNumber(createdBefore),\n resolveWithFullInfo: resolveWithFullInfo ?? false,\n };\n\n if (first != null && typeof options.first !== 'number') {\n throw new Error('Option \"first\" must be a number!');\n }\n if (after != null && typeof options.after !== 'string') {\n throw new Error('Option \"after\" must be a string!');\n }\n if (album != null && typeof options.album !== 'string') {\n throw new Error('Option \"album\" must be a string!');\n }\n if (after != null && Platform.OS === 'android' && isNaN(parseInt(getId(after) as string, 10))) {\n throw new Error('Option \"after\" must be a valid ID!');\n }\n if (first != null && first < 0) {\n throw new Error('Option \"first\" must be a positive integer!');\n }\n\n options.mediaType.forEach(checkMediaType);\n // TODO(@kitten): Add expected native types for `MediaLibrary`\n return await MediaLibrary.getAssetsAsync({\n ...options,\n sortBy: options.sortBy.map(sortByOptionToString),\n });\n}\n\n// @needsAudit\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS, it's invoked with [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent)\n * object.\n *\n * Additionally, only on iOS, the listener is also invoked when the user changes access to individual assets in media library\n * using `presentPermissionsPickerAsync()`.\n * @return An [`Subscription`](#subscription) object that you can call `remove()` on when you would\n * like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return MediaLibrary.addListener(MediaLibrary.CHANGE_LISTENER_NAME, listener);\n}\n\n/**\n */\nexport function removeSubscription(subscription: EventSubscription): void {\n subscription.remove();\n}\n\n// @needsAudit\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n MediaLibrary.removeAllListeners(MediaLibrary.CHANGE_LISTENER_NAME);\n}\n\n// @needsAudit\n/**\n * Fetches a list of moments, which is a group of assets taken around the same place\n * and time.\n * @return An array of [albums](#album) whose type is `moment`.\n * @platform ios\n */\nexport async function getMomentsAsync() {\n if (!MediaLibrary.getMomentsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getMomentsAsync');\n }\n\n return await MediaLibrary.getMomentsAsync();\n}\n\n// @needsAudit\n/**\n * Moves album content to the special media directories on **Android R** or **above** if needed.\n * Those new locations are in line with the Android `scoped storage` - so your application won't\n * lose write permission to those directories in future.\n *\n * This method does nothing if:\n * - app is running on **iOS**, **web** or **Android below R**\n * - app has **write permission** to the album folder\n *\n * The migration is possible when the album contains only compatible files types.\n * For instance, movies and pictures are compatible with each other, but music and pictures are not.\n * If automatic migration isn't possible, the function rejects.\n * In that case, you can use methods from the `expo-file-system` to migrate all your files manually.\n *\n * # Why do you need to migrate files?\n * __Android R__ introduced a lot of changes in storage system. Now applications can't save\n * anything to the root directory. The only available locations are from the `MediaStore` API.\n * Unfortunately, the media library stored albums in folders for which, because of those changes,\n * the application doesn't have permissions anymore. However, it doesn't mean you need to migrate\n * all your albums. If your application doesn't add assets to albums, you don't have to migrate.\n * Everything will work as it used to. You can read more about scoped storage in [the Android documentation](https://developer.android.com/about/versions/11/privacy/storage).\n *\n * @param album An [Album](#album) or its ID.\n * @return A promise which fulfils to `void`.\n */\nexport async function migrateAlbumIfNeededAsync(album: AlbumRef): Promise {\n if (!MediaLibrary.migrateAlbumIfNeededAsync) {\n return;\n }\n\n return await MediaLibrary.migrateAlbumIfNeededAsync(getId(album));\n}\n\n// @needsAudit\n/**\n * Checks if the album should be migrated to a different location. In other words, it checks if the\n * application has the write permission to the album folder. If not, it returns `true`, otherwise `false`.\n * > Note: For **Android below R**, **web** or **iOS**, this function always returns `false`.\n * @param album An [Album](#album) or its ID.\n * @return Returns a promise which fulfils with `true` if the album should be migrated.\n */\nexport async function albumNeedsMigrationAsync(album: AlbumRef): Promise {\n if (!MediaLibrary.albumNeedsMigrationAsync) {\n return false;\n }\n\n return await MediaLibrary.albumNeedsMigrationAsync(getId(album));\n}\n\n/**\n * On iOS, this adds or removes the asset from the system \"Favorites\" smart album.\n * @param asset An [Asset](#asset) or its ID.\n * @param isFavorite Whether the asset should be marked as favorite.\n * @platform ios\n * @return Returns a promise which fulfils with `true` if the operation was successful.\n */\nexport async function setAssetFavoriteAsync(\n asset: AssetRef,\n isFavorite: boolean\n): Promise {\n if (!MediaLibrary.setAssetFavoriteAsync) {\n throw new UnavailabilityError('MediaLibrary', 'setAssetFavoriteAsync');\n }\n\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'setAssetFavoriteAsync is only available on iOS');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n return await MediaLibrary.setAssetFavoriteAsync(assetId, isFavorite);\n}\n"]} \ No newline at end of file +{"version":3,"file":"MediaLibrary.js","sourceRoot":"","sources":["../../src/legacy/MediaLibrary.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmD,oBAAoB,EAAE,MAAM,MAAM,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAA0B,MAAM,mBAAmB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAE9C,MAAM,QAAQ,GAAG,OAAO,IAAI,KAAK,WAAW,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC;AAEjF,IAAI,mBAAmB,GAAG,KAAK,CAAC;AAEhC,IAAI,QAAQ,IAAI,CAAC,mBAAmB,EAAE,CAAC;IACrC,OAAO,CAAC,IAAI,CACV,wQAAwQ,CACzQ,CAAC;IACF,mBAAmB,GAAG,IAAI,CAAC;AAC7B,CAAC;AA0VD,4CAA4C;AAC5C,OAAO,EACL,gBAAgB,GAIjB,MAAM,MAAM,CAAC;AACd,OAAO,EAA0C,MAAM,mBAAmB,CAAC;AAE3E,SAAS,QAAQ,CAAI,IAAa;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5B,CAAC;AAED,SAAS,KAAK,CAAC,GAAyC;IACtD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,CAAC;AAED,SAAS,aAAa,CAAC,QAAmB;IACxC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,QAAmB;IACxC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,SAAkB;IACxC,IAAI,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,SAAgB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAe;IAClC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAE1B,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;SAAM,CAAC;QACN,cAAc,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAAW;IACjC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,MAA+B;IAC3D,WAAW,CAAC,MAAM,CAAC,CAAC;IACpB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACtD,CAAC;IACD,OAAO,GAAG,MAAM,OAAO,CAAC;AAC1B,CAAC;AAED,SAAS,YAAY,CAAC,KAAqB;IACzC,OAAO,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACzD,CAAC;AAED,cAAc;AACd;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAoB,YAAY,CAAC,SAAS,CAAC;AAEjE,cAAc;AACd;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAiB,YAAY,CAAC,MAAM,CAAC;AAExD,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,CAAC,CAAC,YAAY,IAAI,gBAAgB,IAAI,YAAY,CAAC;AAC5D,CAAC;AAED,2BAA2B;AAC3B;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,YAAY,CAAC,uBAAuB,EAAE,CAAC;QAC1C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAC/D,CAAC;AAED,2BAA2B;AAC3B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,YAAY,CAAC,mBAAmB,EAAE,CAAC;QACtC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;AAC3D,CAAC;AAED,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAGhD;IACA,4FAA4F;IAC5F,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;IAC7F,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CACzB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;CAC5E,CAAC,CAAC;AAEH,cAAc;AACd;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,aAAgC,CAAC,OAAO,EAAE,OAAO,CAAC;IAElD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1C,MAAM,IAAI,mBAAmB,CAC3B,cAAc,EACd,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,QAAQ,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QACxD,MAAM,YAAY,CAAC,uBAAuB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAC9D,OAAO;IACT,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,6BAA6B,EAAE,CAAC;QAChD,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,+BAA+B,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,6BAA6B,EAAE,CAAC;AAC5D,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB,EAAE,KAAgB;IACvE,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAErE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,sEAAsE;QACtE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,cAAc;AACd;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAgB;IACvD,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;QACrC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,oBAAoB,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,MAA6B,EAC7B,KAAe,EACf,OAAgB,IAAI;IAEpB,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IACzE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,QAAQ,CAAC,CAAC;IAExB,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,cAAc;AACd;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAA6B,EAC7B,KAAe;IAEf,IAAI,CAAC,YAAY,CAAC,0BAA0B,EAAE,CAAC;QAC7C,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,4BAA4B,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,MAAM,YAAY,CAAC,0BAA0B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAA6B;IACnE,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE7C,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAe,EACf,UAA6C,EAAE,yBAAyB,EAAE,IAAI,EAAE;IAEhF,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzB,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAEzE,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,2EAA2E;QAC3E,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAE,kBAAkB,GAAG,KAAK,KAAoB,EAAE;IAGrF,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC,CAAC;AACnE,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,IAAI,CAAC,YAAY,CAAC,aAAa,EAAE,CAAC;QAChC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACjD,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,SAAiB,EACjB,KAAgB,EAChB,YAAqB,IAAI,EACzB,oBAA6B;IAE7B,IAAI,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,IACE,QAAQ,CAAC,EAAE,KAAK,SAAS;QACzB,CAAC,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC;QACrD,CAAC,oBAAoB,EACrB,CAAC;QACD,wFAAwF;QACxF,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO,MAAM,YAAY,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AACpG,CAAC;AAED,cAAc;AACd;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA6B,EAC7B,cAAuB,KAAK;IAE5B,IAAI,CAAC,YAAY,CAAC,iBAAiB,EAAE,CAAC;QACpC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAE7C,aAAa,CAAC,QAAQ,CAAC,CAAC;IACxB,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,MAAM,YAAY,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC;AAED,cAAc;AACd;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,gBAA+B,EAAE;IACpE,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC;QACjC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,EACJ,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,YAAY,EACZ,aAAa,EACb,aAAa,EACb,mBAAmB,GACpB,GAAG,aAAa,CAAC;IAElB,MAAM,OAAO,GAAG;QACd,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK;QACjC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;QACnB,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;QACnB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;QACxB,SAAS,EAAE,QAAQ,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACnD,aAAa,EAAE,QAAQ,CAAC,aAAa,CAAC;QACtC,YAAY,EAAE,YAAY,CAAC,YAAY,CAAC;QACxC,aAAa,EAAE,YAAY,CAAC,aAAa,CAAC;QAC1C,mBAAmB,EAAE,mBAAmB,IAAI,KAAK;KAClD,CAAC;IAEF,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAW,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;QAC9F,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC1C,8DAA8D;IAC9D,OAAO,MAAM,YAAY,CAAC,cAAc,CAAC;QACvC,GAAG,OAAO;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC;KACjD,CAAC,CAAC;AACL,CAAC;AAED,cAAc;AACd;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CACzB,QAAwD;IAExD,OAAO,YAAY,CAAC,WAAW,CAAC,YAAY,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED;GACG;AACH,MAAM,UAAU,kBAAkB,CAAC,YAA+B;IAChE,YAAY,CAAC,MAAM,EAAE,CAAC;AACxB,CAAC;AAED,cAAc;AACd;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,YAAY,CAAC,kBAAkB,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC;AACrE,CAAC;AAED,cAAc;AACd;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,eAAe,EAAE,CAAC;AAC9C,CAAC;AAED,cAAc;AACd;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,KAAe;IAC7D,IAAI,CAAC,YAAY,CAAC,yBAAyB,EAAE,CAAC;QAC5C,OAAO;IACT,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,yBAAyB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,cAAc;AACd;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAe;IAC5D,IAAI,CAAC,YAAY,CAAC,wBAAwB,EAAE,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,MAAM,YAAY,CAAC,wBAAwB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,KAAe,EACf,UAAmB;IAEnB,IAAI,CAAC,YAAY,CAAC,qBAAqB,EAAE,CAAC;QACxC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uBAAuB,CAAC,CAAC;IACzE,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,gDAAgD,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAE7B,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzB,OAAO,MAAM,YAAY,CAAC,qBAAqB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import { type PermissionResponse as EXPermissionResponse, createPermissionHook } from 'expo';\nimport { UnavailabilityError, type EventSubscription } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport MediaLibrary from './ExpoMediaLibrary';\n\nconst isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo;\n\nlet loggedExpoGoWarning = false;\n\nif (isExpoGo && !loggedExpoGoWarning) {\n console.warn(\n 'Due to changes in Androids permission requirements, Expo Go can no longer provide full access to the media library. To test the full functionality of this module, you can create a development build. https://docs.expo.dev/develop/development-builds/create-a-build'\n );\n loggedExpoGoWarning = true;\n}\n\n// @needsAudit\nexport type PermissionResponse = EXPermissionResponse & {\n /**\n * Indicates if your app has access to the whole or only part of the photo library. Possible values are:\n * - `'all'` if the user granted your app access to the whole photo library\n * - `'limited'` if the user granted your app access only to selected photos (only available on Android API 14+ and iOS 14.0+)\n * - `'none'` if user denied or hasn't yet granted the permission\n */\n accessPrivileges?: 'all' | 'limited' | 'none';\n};\n\n/**\n * Determines the type of media that the app will ask the OS to get access to.\n * @platform android 13+\n */\nexport type GranularPermission = 'audio' | 'photo' | 'video';\n\nexport type MediaTypeValue = 'audio' | 'photo' | 'video' | 'unknown' | 'pairedVideo';\n\n/**\n * Represents the possible types of media that the app will ask the OS to get access to when calling [`presentPermissionsPickerAsync()`](#medialibrarypresentpermissionspickerasyncmediatypes).\n * @platform android 14+\n * */\nexport type MediaTypeFilter = 'photo' | 'video';\n\nexport type SortByKey =\n | 'default'\n | 'mediaType'\n | 'width'\n | 'height'\n | 'creationTime'\n | 'modificationTime'\n | 'duration';\nexport type SortByValue = [SortByKey, boolean] | SortByKey;\n\ntype InternalSortByValue = `${SortByKey} ${'ASC' | 'DESC'}`;\n\nexport type MediaTypeObject = {\n audio: 'audio';\n photo: 'photo';\n video: 'video';\n unknown: 'unknown';\n};\n\nexport type SortByObject = {\n default: 'default';\n mediaType: 'mediaType';\n width: 'width';\n height: 'height';\n creationTime: 'creationTime';\n modificationTime: 'modificationTime';\n duration: 'duration';\n};\n\n// @needsAudit\nexport type Asset = {\n /**\n * Internal ID that represents an asset.\n */\n id: string;\n /**\n * Filename of the asset.\n */\n filename: string;\n /**\n * URI that points to the asset. `ph://*` (iOS), `file://*` (Android)\n */\n uri: string;\n /**\n * Media type.\n */\n mediaType: MediaTypeValue;\n /**\n * An array of media subtypes.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[];\n /**\n * Width of the image or video.\n */\n width: number;\n /**\n * Height of the image or video.\n */\n height: number;\n /**\n * File creation timestamp.\n */\n creationTime: number;\n /**\n * Last modification timestamp.\n */\n modificationTime: number;\n /**\n * Duration of the video or audio asset in seconds.\n */\n duration: number;\n /**\n * Album ID that the asset belongs to.\n * @platform android\n */\n albumId?: string;\n};\n\n// @needsAudit\nexport type AssetInfo = Asset & {\n /**\n * Local URI for the asset.\n */\n localUri?: string;\n /**\n * GPS location if available.\n */\n location?: Location;\n /**\n * EXIF metadata associated with the image.\n */\n exif?: object;\n /**\n * Whether the asset is marked as favorite.\n * @platform ios\n */\n isFavorite?: boolean;\n /**\n * This field is available only if flag `shouldDownloadFromNetwork` is set to `false`.\n * Whether the asset is stored on the network (iCloud on iOS).\n * @platform ios\n */\n isNetworkAsset?: boolean; //iOS only\n /**\n * Display orientation of the image. Orientation is available only for assets whose\n * `mediaType` is `MediaType.photo`. Value will range from 1 to 8, see [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html)\n * for more details.\n * @platform ios\n */\n orientation?: number;\n /**\n * Contains information about the video paired with the image file.\n * This field is available if the `mediaType` is `\"photo\"`, and the `mediaSubtypes` includes `\"livePhoto\"`.\n * @platform ios\n */\n pairedVideoAsset?: Asset | null;\n};\n\n/**\n * Constants identifying specific variations of asset media, such as panorama or screenshot photos,\n * and time-lapse or high-frame-rate video. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype#1603888).\n * @platform ios\n * */\nexport type MediaSubtype =\n | 'depthEffect'\n | 'hdr'\n | 'highFrameRate'\n | 'livePhoto'\n | 'panorama'\n | 'screenshot'\n | 'stream'\n | 'timelapse'\n | 'spatialMedia'\n | 'videoCinematic';\n\n// @needsAudit\nexport type MediaLibraryAssetInfoQueryOptions = {\n /**\n * Whether allow the asset to be downloaded from network. Only available in iOS with iCloud assets.\n * @default true\n */\n shouldDownloadFromNetwork?: boolean;\n};\n\n// @needsAudit\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes could be described as \"incremental changes\".\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload (eg. a user has changed access to individual assets in the\n * media library).\n */\n hasIncrementalChanges: boolean;\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been inserted to the library.\n */\n insertedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been deleted from the library.\n */\n deletedAssets?: Asset[];\n /**\n * Available only if `hasIncrementalChanges` is `true`.\n * Array of [`Asset`](#asset)s that have been updated or completed downloading from network\n * storage (iCloud on iOS).\n */\n updatedAssets?: Asset[];\n};\n\n// @docsMissing\nexport type Location = {\n latitude: number;\n longitude: number;\n};\n\n// @needsAudit\nexport type Album = {\n /**\n * Album ID.\n */\n id: string;\n /**\n * Album title.\n */\n title: string;\n /**\n * Estimated number of assets in album.\n */\n assetCount: number;\n /**\n * The type of the assets album.\n * @platform ios\n */\n type?: AlbumType;\n /**\n * Apply only to albums whose type is `'moment'`. Earliest creation timestamp of all\n * assets in moment.\n * @platform ios\n */\n startTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Latest creation timestamp of all\n * assets in moment.\n * @platform ios\n */\n endTime: number;\n /**\n * Apply only to albums whose type is `'moment'`. Approximated location of all\n * assets in moment.\n * @platform ios\n */\n approximateLocation?: Location;\n /**\n * Apply only to albums whose type is `'moment'`. Names of locations grouped\n * in moment.\n * @platform ios\n */\n locationNames?: string[];\n};\n\n// @docsMissing\nexport type AlbumType = 'album' | 'moment' | 'smartAlbum';\n\n// @docsMissing\nexport type AlbumsOptions = {\n includeSmartAlbums?: boolean;\n};\n\n// @needsAudit\nexport type AssetsOptions = {\n /**\n * The maximum number of items on a single page.\n * @default 20\n */\n first?: number;\n /**\n * Asset ID of the last item returned on the previous page. To get the ID of the next page,\n * pass [`endCursor`](#pagedinfo) as its value.\n */\n after?: AssetRef;\n /**\n * [Album](#album) or its ID to get assets from specific album.\n */\n album?: AlbumRef;\n /**\n * An array of [`SortByValue`](#sortbyvalue)s or a single `SortByValue` value. By default, all\n * keys are sorted in descending order, however you can also pass a pair `[key, ascending]` where\n * the second item is a `boolean` value that means whether to use ascending order. Note that if\n * the `SortBy.default` key is used, then `ascending` argument will not matter. Earlier items have\n * higher priority when sorting out the results.\n * If empty, this method uses the default sorting that is provided by the platform.\n */\n sortBy?: SortByValue[] | SortByValue;\n /**\n * An array of [MediaTypeValue](#mediatypevalue)s or a single `MediaTypeValue`.\n * @default MediaType.photo\n */\n mediaType?: MediaTypeValue[] | MediaTypeValue;\n /**\n * An array of [MediaSubtype](#mediasubtype)s or a single `MediaSubtype`.\n * @platform ios\n */\n mediaSubtypes?: MediaSubtype[] | MediaSubtype;\n /**\n * `Date` object or Unix timestamp in milliseconds limiting returned assets only to those that\n * were created after this date.\n */\n createdAfter?: Date | number;\n /**\n * Similarly as `createdAfter`, but limits assets only to those that were created before specified\n * date.\n */\n createdBefore?: Date | number;\n /**\n * Whether to resolve full info for the assets during the query.\n * This is useful to get the full EXIF data for images. It can fix the orientation of the image.\n * @default false\n * @platform android\n */\n resolveWithFullInfo?: boolean;\n};\n\n// @needsAudit\nexport type PagedInfo = {\n /**\n * A page of [`Asset`](#asset)s fetched by the query.\n */\n assets: T[];\n /**\n * A marker that indicates where the next page of results should start.\n * On iOS, it is the ID of the last fetched asset.\n * On Android, it is the index of the last fetched asset in query results.\n * This value should be passed as the `after` option to load the next page.\n */\n endCursor: string;\n /**\n * Whether there are more assets to fetch.\n */\n hasNextPage: boolean;\n /**\n * Estimated total number of assets that match the query.\n */\n totalCount: number;\n};\n\n/**\n * @hidden\n */\nexport type AssetRef = Asset | string;\n\n/**\n * @hidden\n */\nexport type AlbumRef = Album | string;\n\n// TODO(@kitten): Remove re-exports from EMC\nexport {\n PermissionStatus,\n type PermissionExpiration,\n type PermissionResponse as EXPermissionResponse,\n type PermissionHookOptions,\n} from 'expo';\nexport { type EventSubscription as Subscription } from 'expo-modules-core';\n\nfunction arrayize(item: T | T[]): T[] {\n if (Array.isArray(item)) {\n return item;\n }\n return item ? [item] : [];\n}\n\nfunction getId(ref: string | undefined | { id?: string }): string | undefined {\n if (typeof ref === 'string') {\n return ref;\n }\n return ref ? ref.id : undefined;\n}\n\nfunction checkAssetIds(assetIds: unknown[]): asserts assetIds is string[] {\n if (assetIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Asset ID must be a string!');\n }\n}\n\nfunction checkAlbumIds(albumIds: unknown[]): asserts albumIds is string[] {\n if (albumIds.some((id) => !id || typeof id !== 'string')) {\n throw new Error('Album ID must be a string!');\n }\n}\n\nfunction checkMediaType(mediaType: unknown): asserts mediaType is keyof MediaTypeObject {\n if (Object.values(MediaType).indexOf(mediaType as any) === -1) {\n throw new Error(`Invalid mediaType: ${mediaType}`);\n }\n}\n\nfunction checkSortBy(sortBy: unknown): asserts sortBy is SortByValue {\n if (Array.isArray(sortBy)) {\n checkSortByKey(sortBy[0]);\n\n if (typeof sortBy[1] !== 'boolean') {\n throw new Error('Invalid sortBy array argument. Second item must be a boolean!');\n }\n } else {\n checkSortByKey(sortBy);\n }\n}\n\nfunction checkSortByKey(sortBy: any): void {\n if (Object.values(SortBy).indexOf(sortBy) === -1) {\n throw new Error(`Invalid sortBy key: ${sortBy}`);\n }\n}\n\nfunction sortByOptionToString(sortBy: SortByValue | undefined): InternalSortByValue {\n checkSortBy(sortBy);\n if (Array.isArray(sortBy)) {\n return `${sortBy[0]} ${sortBy[1] ? 'ASC' : 'DESC'}`;\n }\n return `${sortBy} DESC`;\n}\n\nfunction dateToNumber(value?: Date | number): number | undefined {\n return value instanceof Date ? value.getTime() : value;\n}\n\n// @needsAudit\n/**\n * Possible media types.\n */\nexport const MediaType: MediaTypeObject = MediaLibrary.MediaType;\n\n// @needsAudit\n/**\n * Supported keys that can be used to sort `getAssetsAsync` results.\n */\nexport const SortBy: SortByObject = MediaLibrary.SortBy;\n\n// @needsAudit\n/**\n * Returns whether the Media Library API is enabled on the current device.\n * @return A promise which fulfils with a `boolean`, indicating whether the Media Library API is\n * available on the current device.\n */\nexport async function isAvailableAsync(): Promise {\n return !!MediaLibrary && 'getAssetsAsync' in MediaLibrary;\n}\n\n// @needsAudit @docsMissing\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n *\n * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in plugin.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!MediaLibrary.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.requestPermissionsAsync(writeOnly);\n}\n\n// @needsAudit @docsMissing\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!MediaLibrary.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await MediaLibrary.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await MediaLibrary.getPermissionsAsync(writeOnly);\n}\n\n// @needsAudit\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions();\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n // TODO(cedric): permission requesters should have an options param or a different requester\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\n// @needsAudit\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPickerAsync(\n mediaTypes: MediaTypeFilter[] = ['photo', 'video']\n): Promise {\n if (Platform.OS === 'android' && isExpoGo) {\n throw new UnavailabilityError(\n 'MediaLibrary',\n 'presentPermissionsPickerAsync is unavailable in Expo Go'\n );\n }\n if (Platform.OS === 'android' && Platform.Version >= 34) {\n await MediaLibrary.requestPermissionsAsync(false, mediaTypes);\n return;\n }\n if (!MediaLibrary.presentPermissionsPickerAsync) {\n throw new UnavailabilityError('MediaLibrary', 'presentPermissionsPickerAsync');\n }\n return await MediaLibrary.presentPermissionsPickerAsync();\n}\n\n// @needsAudit\n/**\n * Creates an asset from existing file. The most common use case is to save a picture taken by [Camera](./camera).\n * This method requires `CAMERA_ROLL` permission.\n *\n * @example\n * ```js\n * const { uri } = await Camera.takePictureAsync();\n * const asset = await MediaLibrary.createAssetAsync(uri);\n * ```\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`\n *\n * @param album An [Album](#album) or its ID. If provided, the asset will be added to this album upon creation, otherwise it will be added to the default album for the media type.\n * The album has exist.\n * @return A promise which fulfils with an object representing an [`Asset`](#asset).\n */\nexport async function createAssetAsync(localUri: string, album?: AlbumRef): Promise {\n if (!MediaLibrary.createAssetAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAssetAsync');\n }\n\n const albumId = getId(album);\n\n if (!localUri || typeof localUri !== 'string') {\n throw new Error('Invalid argument \"localUri\". It must be a string!');\n }\n const asset = await MediaLibrary.createAssetAsync(localUri, albumId);\n\n if (Array.isArray(asset)) {\n // Android returns an array with asset, we need to pick the first item\n return asset[0];\n }\n return asset;\n}\n\n// @needsAudit\n/**\n * Saves the file at given `localUri` to the user's media library. Unlike `createAssetAsync()`,\n * This method doesn't return created asset.\n * On __iOS 11+__, it's possible to use this method without asking for `CAMERA_ROLL` permission,\n * however then yours `Info.plist` should have `NSPhotoLibraryAddUsageDescription` key.\n * @param localUri A URI to the image or video file. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`.\n */\nexport async function saveToLibraryAsync(localUri: string): Promise {\n if (!MediaLibrary.saveToLibraryAsync) {\n throw new UnavailabilityError('MediaLibrary', 'saveToLibraryAsync');\n }\n return await MediaLibrary.saveToLibraryAsync(localUri);\n}\n\n// @needsAudit\n/**\n * Adds array of assets to the album.\n *\n * On Android, by default it copies assets from the current album to provided one, however it's also\n * possible to move them by passing `false` as `copyAssets` argument. In case they're copied you\n * should keep in mind that `getAssetsAsync` will return duplicated assets.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @param copy __Android only.__ Whether to copy assets to the new album instead of move them.\n * Defaults to `true`.\n * @return Returns promise which fulfils with `true` if the assets were successfully added to\n * the album.\n */\nexport async function addAssetsToAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef,\n copy: boolean = true\n): Promise {\n if (!MediaLibrary.addAssetsToAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'addAssetsToAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n\n if (!albumId || typeof albumId !== 'string') {\n throw new Error('Invalid album ID. It must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId);\n }\n return await MediaLibrary.addAssetsToAlbumAsync(assetIds, albumId, !!copy);\n}\n\n// @needsAudit\n/**\n * Removes given assets from album.\n *\n * On Android, album will be automatically deleted if there are no more assets inside.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @param album An [Album](#album) or its ID.\n * @return Returns promise which fulfils with `true` if the assets were successfully removed from\n * the album.\n */\nexport async function removeAssetsFromAlbumAsync(\n assets: AssetRef[] | AssetRef,\n album: AlbumRef\n): Promise {\n if (!MediaLibrary.removeAssetsFromAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'removeAssetsFromAlbumAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n const albumId = getId(album);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.removeAssetsFromAlbumAsync(assetIds, albumId);\n}\n\n// @needsAudit\n/**\n * Deletes assets from the library. On iOS it deletes assets from all albums they belong to, while\n * on Android it keeps all copies of them (album is strictly connected to the asset). Also, there is\n * additional dialog on iOS that requires user to confirm this action.\n * @param assets An array of [Asset](#asset) or their IDs.\n * @return Returns promise which fulfils with `true` if the assets were successfully deleted.\n */\nexport async function deleteAssetsAsync(assets: AssetRef[] | AssetRef): Promise {\n if (!MediaLibrary.deleteAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAssetsAsync');\n }\n\n const assetIds = arrayize(assets).map(getId);\n\n checkAssetIds(assetIds);\n return await MediaLibrary.deleteAssetsAsync(assetIds);\n}\n\n// @needsAudit\n/**\n * Provides more information about an asset, including GPS location, local URI and EXIF metadata.\n * For better performance, prefer using individual getters such as `asset.getLocation()` or `asset.getExif()` to fetch only the data you need.\n * @param asset An [Asset](#asset) or its ID.\n * @param options\n * @return An [AssetInfo](#assetinfo) object, which is an `Asset` extended by an additional fields.\n */\nexport async function getAssetInfoAsync(\n asset: AssetRef,\n options: MediaLibraryAssetInfoQueryOptions = { shouldDownloadFromNetwork: true }\n): Promise {\n if (!MediaLibrary.getAssetInfoAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetInfoAsync');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n const assetInfo = await MediaLibrary.getAssetInfoAsync(assetId, options);\n\n if (Array.isArray(assetInfo)) {\n // Android returns an array with asset info, we need to pick the first item\n return assetInfo[0];\n }\n return assetInfo;\n}\n\n// @needsAudit\n/**\n * Queries for user-created albums in media gallery.\n * @return A promise which fulfils with an array of [`Album`](#asset)s. Depending on Android version,\n * root directory of your storage may be listed as album titled `\"0\"` or unlisted at all.\n */\nexport async function getAlbumsAsync({ includeSmartAlbums = false }: AlbumsOptions = {}): Promise<\n Album[]\n> {\n if (!MediaLibrary.getAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumsAsync');\n }\n return await MediaLibrary.getAlbumsAsync({ includeSmartAlbums });\n}\n\n// @needsAudit\n/**\n * Queries for an album with a specific name.\n * @param title Name of the album to look for.\n * @return An object representing an [`Album`](#album), if album with given name exists, otherwise\n * returns `null`.\n */\nexport async function getAlbumAsync(title: string): Promise {\n if (!MediaLibrary.getAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAlbumAsync');\n }\n if (typeof title !== 'string') {\n throw new Error('Album title must be a string!');\n }\n return await MediaLibrary.getAlbumAsync(title);\n}\n\n// @needsAudit\n/**\n * Creates an album with given name and initial asset. The asset parameter is required on Android,\n * since it's not possible to create empty album on this platform. On Android, by default it copies\n * given asset from the current album to the new one, however it's also possible to move it by\n * passing `false` as `copyAsset` argument.\n * In case it's copied you should keep in mind that `getAssetsAsync` will return duplicated asset.\n * > On Android, it's not possible to create an empty album. You must provide an existing asset to copy or move into the album or an uri of a local file, which will be used to create an initial asset for the album.\n * @param albumName Name of the album to create.\n * @param asset An [Asset](#asset) or its ID. On Android you either need to provide an asset or a localUri.\n * @param initialAssetLocalUri A URI to the local media file, which will be used to create the initial asset inside the album. It must contain an extension. On Android it\n * must be a local path, so it must start with `file:///`. If the `asset` was provided, this parameter will be ignored.\n * @param copyAsset __Android Only.__ Whether to copy asset to the new album instead of move it. This parameter is ignored if `asset` was not provided.\n * Defaults to `true`.\n * @return Newly created [`Album`](#album).\n */\nexport async function createAlbumAsync(\n albumName: string,\n asset?: AssetRef,\n copyAsset: boolean = true,\n initialAssetLocalUri?: string\n): Promise {\n if (!MediaLibrary.createAlbumAsync) {\n throw new UnavailabilityError('MediaLibrary', 'createAlbumAsync');\n }\n\n const assetId = getId(asset);\n\n if (\n Platform.OS === 'android' &&\n (typeof assetId !== 'string' || assetId.length === 0) &&\n !initialAssetLocalUri\n ) {\n // it's not possible to create empty album on Android, so initial asset must be provided\n throw new Error(\n 'MediaLibrary.createAlbumAsync must be called with an asset or a localUri on Android.'\n );\n }\n if (!albumName || typeof albumName !== 'string') {\n throw new Error('Invalid argument \"albumName\". It must be a string!');\n }\n if (assetId != null && typeof assetId !== 'string') {\n throw new Error('Asset ID must be a string!');\n }\n\n if (Platform.OS === 'ios') {\n return await MediaLibrary.createAlbumAsync(albumName, assetId, initialAssetLocalUri);\n }\n return await MediaLibrary.createAlbumAsync(albumName, assetId, !!copyAsset, initialAssetLocalUri);\n}\n\n// @needsAudit\n/**\n * Deletes given albums from the library. On Android by default it deletes assets belonging to given\n * albums from the library. On iOS it doesn't delete these assets, however it's possible to do by\n * passing `true` as `deleteAssets`.\n * @param albums An array of [`Album`](#asset)s or their IDs.\n * @param assetRemove __iOS Only.__ Whether to also delete assets belonging to given albums.\n * Defaults to `false`.\n * @return Returns a promise which fulfils with `true` if the albums were successfully deleted from\n * the library.\n */\nexport async function deleteAlbumsAsync(\n albums: AlbumRef[] | AlbumRef,\n assetRemove: boolean = false\n): Promise {\n if (!MediaLibrary.deleteAlbumsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'deleteAlbumsAsync');\n }\n\n const albumIds = arrayize(albums).map(getId);\n\n checkAlbumIds(albumIds);\n if (Platform.OS === 'android') {\n return await MediaLibrary.deleteAlbumsAsync(albumIds);\n }\n return await MediaLibrary.deleteAlbumsAsync(albumIds, !!assetRemove);\n}\n\n// @needsAudit\n/**\n * Fetches a page of assets matching the provided criteria.\n * @param assetsOptions\n * @return A promise that fulfils with to [`PagedInfo`](#pagedinfo) object with array of [`Asset`](#asset)s.\n */\nexport async function getAssetsAsync(assetsOptions: AssetsOptions = {}): Promise> {\n if (!MediaLibrary.getAssetsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getAssetsAsync');\n }\n\n const {\n first,\n after,\n album,\n sortBy,\n mediaType,\n createdAfter,\n createdBefore,\n mediaSubtypes,\n resolveWithFullInfo,\n } = assetsOptions;\n\n const options = {\n first: first == null ? 20 : first,\n after: getId(after),\n album: getId(album),\n sortBy: arrayize(sortBy),\n mediaType: arrayize(mediaType || [MediaType.photo]),\n mediaSubtypes: arrayize(mediaSubtypes),\n createdAfter: dateToNumber(createdAfter),\n createdBefore: dateToNumber(createdBefore),\n resolveWithFullInfo: resolveWithFullInfo ?? false,\n };\n\n if (first != null && typeof options.first !== 'number') {\n throw new Error('Option \"first\" must be a number!');\n }\n if (after != null && typeof options.after !== 'string') {\n throw new Error('Option \"after\" must be a string!');\n }\n if (album != null && typeof options.album !== 'string') {\n throw new Error('Option \"album\" must be a string!');\n }\n if (after != null && Platform.OS === 'android' && isNaN(parseInt(getId(after) as string, 10))) {\n throw new Error('Option \"after\" must be a valid ID!');\n }\n if (first != null && first < 0) {\n throw new Error('Option \"first\" must be a positive integer!');\n }\n\n options.mediaType.forEach(checkMediaType);\n // TODO(@kitten): Add expected native types for `MediaLibrary`\n return await MediaLibrary.getAssetsAsync({\n ...options,\n sortBy: options.sortBy.map(sortByOptionToString),\n });\n}\n\n// @needsAudit\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS, it's invoked with [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent)\n * object.\n *\n * Additionally, only on iOS, the listener is also invoked when the user changes access to individual assets in media library\n * using `presentPermissionsPickerAsync()`.\n * @return An [`Subscription`](#subscription) object that you can call `remove()` on when you would\n * like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return MediaLibrary.addListener(MediaLibrary.CHANGE_LISTENER_NAME, listener);\n}\n\n/**\n */\nexport function removeSubscription(subscription: EventSubscription): void {\n subscription.remove();\n}\n\n// @needsAudit\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n MediaLibrary.removeAllListeners(MediaLibrary.CHANGE_LISTENER_NAME);\n}\n\n// @needsAudit\n/**\n * Fetches a list of moments, which is a group of assets taken around the same place\n * and time.\n * @return An array of [albums](#album) whose type is `moment`.\n * @platform ios\n */\nexport async function getMomentsAsync() {\n if (!MediaLibrary.getMomentsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getMomentsAsync');\n }\n\n return await MediaLibrary.getMomentsAsync();\n}\n\n// @needsAudit\n/**\n * Moves album content to the special media directories on **Android R** or **above** if needed.\n * Those new locations are in line with the Android `scoped storage` - so your application won't\n * lose write permission to those directories in future.\n *\n * This method does nothing if:\n * - app is running on **iOS**, **web** or **Android below R**\n * - app has **write permission** to the album folder\n *\n * The migration is possible when the album contains only compatible files types.\n * For instance, movies and pictures are compatible with each other, but music and pictures are not.\n * If automatic migration isn't possible, the function rejects.\n * In that case, you can use methods from the `expo-file-system` to migrate all your files manually.\n *\n * # Why do you need to migrate files?\n * __Android R__ introduced a lot of changes in storage system. Now applications can't save\n * anything to the root directory. The only available locations are from the `MediaStore` API.\n * Unfortunately, the media library stored albums in folders for which, because of those changes,\n * the application doesn't have permissions anymore. However, it doesn't mean you need to migrate\n * all your albums. If your application doesn't add assets to albums, you don't have to migrate.\n * Everything will work as it used to. You can read more about scoped storage in [the Android documentation](https://developer.android.com/about/versions/11/privacy/storage).\n *\n * @param album An [Album](#album) or its ID.\n * @return A promise which fulfils to `void`.\n */\nexport async function migrateAlbumIfNeededAsync(album: AlbumRef): Promise {\n if (!MediaLibrary.migrateAlbumIfNeededAsync) {\n return;\n }\n\n return await MediaLibrary.migrateAlbumIfNeededAsync(getId(album));\n}\n\n// @needsAudit\n/**\n * Checks if the album should be migrated to a different location. In other words, it checks if the\n * application has the write permission to the album folder. If not, it returns `true`, otherwise `false`.\n * > Note: For **Android below R**, **web** or **iOS**, this function always returns `false`.\n * @param album An [Album](#album) or its ID.\n * @return Returns a promise which fulfils with `true` if the album should be migrated.\n */\nexport async function albumNeedsMigrationAsync(album: AlbumRef): Promise {\n if (!MediaLibrary.albumNeedsMigrationAsync) {\n return false;\n }\n\n return await MediaLibrary.albumNeedsMigrationAsync(getId(album));\n}\n\n/**\n * On iOS, this adds or removes the asset from the system \"Favorites\" smart album.\n * @param asset An [Asset](#asset) or its ID.\n * @param isFavorite Whether the asset should be marked as favorite.\n * @platform ios\n * @return Returns a promise which fulfils with `true` if the operation was successful.\n */\nexport async function setAssetFavoriteAsync(\n asset: AssetRef,\n isFavorite: boolean\n): Promise {\n if (!MediaLibrary.setAssetFavoriteAsync) {\n throw new UnavailabilityError('MediaLibrary', 'setAssetFavoriteAsync');\n }\n\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'setAssetFavoriteAsync is only available on iOS');\n }\n\n const assetId = getId(asset);\n\n checkAssetIds([assetId]);\n\n return await MediaLibrary.setAssetFavoriteAsync(assetId, isFavorite);\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/index.d.ts b/packages/expo-media-library/build/next/index.d.ts index b8b9ed8c9b3893..fcee4568983aff 100644 --- a/packages/expo-media-library/build/next/index.d.ts +++ b/packages/expo-media-library/build/next/index.d.ts @@ -1,2 +1,3 @@ -export * from '..'; +export { Asset, Album, Query, requestPermissionsAsync, getPermissionsAsync, usePermissions, presentPermissionsPicker, addListener, removeAllListeners, } from './js'; +export { AssetField, MediaSubtype, MediaType, type Shape, type Location, type AssetFieldValueMap, type AssetInfo, type GranularPermission, type MediaLibraryAssetsChangeEvent, type MediaTypeFilter, PermissionStatus, type EventSubscription, type PermissionExpiration, type PermissionHookOptions, type PermissionResponse, type SortDescriptor, type Subscription, } from './types'; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/index.d.ts.map b/packages/expo-media-library/build/next/index.d.ts.map index 2119c1c66527da..0c5f95e8cce6e0 100644 --- a/packages/expo-media-library/build/next/index.d.ts.map +++ b/packages/expo-media-library/build/next/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,cAAc,IAAI,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,wBAAwB,EACxB,WAAW,EACX,kBAAkB,GACnB,MAAM,MAAM,CAAC;AAEd,OAAO,EACL,UAAU,EACV,YAAY,EACZ,SAAS,EACT,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,SAAS,EACd,KAAK,kBAAkB,EACvB,KAAK,6BAA6B,EAClC,KAAK,eAAe,EACpB,gBAAgB,EAChB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/index.js b/packages/expo-media-library/build/next/index.js index 5ac5bb80e06b28..aa039f11dc5af9 100644 --- a/packages/expo-media-library/build/next/index.js +++ b/packages/expo-media-library/build/next/index.js @@ -1,2 +1,3 @@ -export * from '..'; +export { Asset, Album, Query, requestPermissionsAsync, getPermissionsAsync, usePermissions, presentPermissionsPicker, addListener, removeAllListeners, } from './js'; +export { AssetField, MediaSubtype, MediaType, PermissionStatus, } from './types'; //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/index.js.map b/packages/expo-media-library/build/next/index.js.map index f828af1da13a13..c31e45a8282d55 100644 --- a/packages/expo-media-library/build/next/index.js.map +++ b/packages/expo-media-library/build/next/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,cAAc,IAAI,CAAC","sourcesContent":["export * from '..';\n"]} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EACL,KAAK,EACL,KAAK,EACL,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,wBAAwB,EACxB,WAAW,EACX,kBAAkB,GACnB,MAAM,MAAM,CAAC;AAEd,OAAO,EACL,UAAU,EACV,YAAY,EACZ,SAAS,EAQT,gBAAgB,GAOjB,MAAM,SAAS,CAAC","sourcesContent":["export {\n Asset,\n Album,\n Query,\n requestPermissionsAsync,\n getPermissionsAsync,\n usePermissions,\n presentPermissionsPicker,\n addListener,\n removeAllListeners,\n} from './js';\n\nexport {\n AssetField,\n MediaSubtype,\n MediaType,\n type Shape,\n type Location,\n type AssetFieldValueMap,\n type AssetInfo,\n type GranularPermission,\n type MediaLibraryAssetsChangeEvent,\n type MediaTypeFilter,\n PermissionStatus,\n type EventSubscription,\n type PermissionExpiration,\n type PermissionHookOptions,\n type PermissionResponse,\n type SortDescriptor,\n type Subscription,\n} from './types';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Album.d.ts b/packages/expo-media-library/build/next/js/Album.d.ts similarity index 78% rename from packages/expo-media-library/build/types/Album.d.ts rename to packages/expo-media-library/build/next/js/Album.d.ts index 18227751b57e59..c37d5c87348791 100644 --- a/packages/expo-media-library/build/types/Album.d.ts +++ b/packages/expo-media-library/build/next/js/Album.d.ts @@ -1,25 +1,26 @@ -import type { Asset } from './Asset'; +import { Asset } from './Asset'; /** * Represents a media album (collection of assets) on the device. * - * An [Album](#album) groups together media assets (images, videos, or audio files). - * To create a new album, use [Album.create](#albumcreate). - * To fetch an existing album, use [Album.get](#albumget). + * An [`Album`](#album) groups together media assets (images, videos, or audio files). + * To create a new album, use `Album.create()`. + * To fetch an existing album, use `Album.get()`. */ export declare class Album { /** - * Reinitialize an instance of an album with a given ID. - * @param id - The unique identifier of the album. + * Unique identifier of the album. + * Can be used to re-instantiate an [`Album`](#album) later. */ - constructor(id: string); + readonly id: string; + private readonly nativeAlbum; /** - * Unique identifier of the album. - * Can be used to re-instantiate an [Album](#album) later. + * Creates an Album instance from its ID. + * @param id - The unique identifier of the album. */ - id: string; + constructor(id: string); /** * Retrieves all assets contained in the album. - * @returns A promise resolving to an array of [Asset](#asset) objects. + * @returns A promise resolving to an array of [`Asset`](#asset) objects. * * @example * ```ts @@ -31,7 +32,7 @@ export declare class Album { /** * Gets the display title (name) of the album. * Note that album titles are not guaranteed to be unique. - * @returns A promise resolving to the album’s title string. + * @returns A promise resolving to the album's title string. * * @example * ```ts @@ -55,7 +56,7 @@ export declare class Album { delete(): Promise; /** * Adds one or more assets to the album. - * @param assets - The [Asset](#asset) or list of [Asset](#asset) objects to add. + * @param assets - The [`Asset`](#asset) or list of [`Asset`](#asset) objects to add. * @returns A promise that resolves once the assets have been added. * * @example @@ -77,7 +78,7 @@ export declare class Album { * On Android, an asset can belong to only one album. To remove it from an album, * delete it or add it to another album. * @platform ios - * @param assets - An array of [Asset](#asset) objects to remove from the album. + * @param assets - An array of [`Asset`](#asset) objects to remove from the album. * @returns A promise that resolves once the assets have been removed. * * @example @@ -92,9 +93,9 @@ export declare class Album { * On Android, if assets are provided and `moveAssets` is true, the assets will be moved into the new album. If false or not supported, the assets will be copied. * * @param name - Name of the new album. - * @param assetsRefs - List of [Asset](#asset) objects or file paths (file:///...) to include. + * @param assetsRefs - List of [`Asset`](#asset) objects or file paths (file:///...) to include. * @param moveAssets - On Android, whether to move assets into the album. Defaults to `true`. - * @returns A promise resolving to the created [Album](#album). + * @returns A promise resolving to the created [`Album`](#album). * * @example * ```ts @@ -106,7 +107,7 @@ export declare class Album { /** * A static function. Deletes multiple albums at once. * On Android, assets are always deleted along with the album regardless of `deleteAssets`. - * @param albums - An array of [Album](#album) instances to delete. + * @param albums - An array of [`Album`](#album) instances to delete. * @param deleteAssets - On iOS, whether to delete the assets in the albums as well. Defaults to `false`. * @returns A promise that resolves once the albums have been deleted. * @@ -120,7 +121,7 @@ export declare class Album { /** * A static function. Retrieves an album by its title. * @param title - The title of the album to retrieve. - * @return A promise resolving to the [Album](#album) if found, or `null` if not found. + * @return A promise resolving to the [`Album`](#album) if found, or `null` if not found. * * @example * ```ts @@ -133,7 +134,7 @@ export declare class Album { static get(title: string): Promise; /** * A static function. Retrieves all albums on the device. - * @returns A promise resolving to an array of [Album](#album) objects. + * @returns A promise resolving to an array of [`Album`](#album) objects. * * @example * ```ts diff --git a/packages/expo-media-library/build/next/js/Album.d.ts.map b/packages/expo-media-library/build/next/js/Album.d.ts.map new file mode 100644 index 00000000000000..7d842522a23868 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Album.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Album.d.ts","sourceRoot":"","sources":["../../../src/next/js/Album.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC;;;;;;GAMG;AACH,qBAAa,KAAK;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAE/D;;;OAGG;gBACS,EAAE,EAAE,MAAM;IAKtB;;;;;;;;;OASG;IACG,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAKnC;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B;;;;;;;;;;;OAWG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;;;;;;;;;;;;;OAeG;IACH,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;;;;;;;;;;;;;OAcG;WACU,MAAM,CACjB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAC9B,UAAU,CAAC,EAAE,OAAO,GACnB,OAAO,CAAC,KAAK,CAAC;IASjB;;;;;;;;;;;;OAYG;WACU,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3E;;;;;;;;;;;;OAYG;WACU,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAKtD;;;;;;;;OAQG;WACU,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAIxC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Album.js b/packages/expo-media-library/build/next/js/Album.js new file mode 100644 index 00000000000000..c6f49f1ccd52bb --- /dev/null +++ b/packages/expo-media-library/build/next/js/Album.js @@ -0,0 +1,178 @@ +import { Asset } from './Asset'; +import { NativeAsset, NativeAlbum } from '../native'; +/** + * Represents a media album (collection of assets) on the device. + * + * An [`Album`](#album) groups together media assets (images, videos, or audio files). + * To create a new album, use `Album.create()`. + * To fetch an existing album, use `Album.get()`. + */ +export class Album { + /** + * Unique identifier of the album. + * Can be used to re-instantiate an [`Album`](#album) later. + */ + id; + nativeAlbum; + /** + * Creates an Album instance from its ID. + * @param id - The unique identifier of the album. + */ + constructor(id) { + this.id = id; + this.nativeAlbum = new NativeAlbum(id); + } + /** + * Retrieves all assets contained in the album. + * @returns A promise resolving to an array of [`Asset`](#asset) objects. + * + * @example + * ```ts + * const assets = await album.getAssets(); + * console.log(assets.length); + * ``` + */ + async getAssets() { + const natives = await this.nativeAlbum.getAssets(); + return natives.map((a) => new Asset(a.id)); + } + /** + * Gets the display title (name) of the album. + * Note that album titles are not guaranteed to be unique. + * @returns A promise resolving to the album's title string. + * + * @example + * ```ts + * const title = await album.getTitle(); + * console.log(title); // "Camera" + * ``` + */ + getTitle() { + return this.nativeAlbum.getTitle(); + } + /** + * Permanently deletes the album from the device. + * On Android, it deletes the album and all its assets. + * On iOS, it deletes the album but keeps the assets in the main library. + * @returns A promise that resolves once the deletion has completed. + * @throws An exception if the deletion fails or the album could not be found. + * + * @example + * ```ts + * await album.delete(); + * ``` + */ + delete() { + return this.nativeAlbum.delete(); + } + /** + * Adds one or more assets to the album. + * @param assets - The [`Asset`](#asset) or list of [`Asset`](#asset) objects to add. + * @returns A promise that resolves once the assets have been added. + * + * @example + * ```ts + * const asset = await Asset.create("file:///path/to/photo.png"); + * await album.add(asset); + * ``` + * + * @example + * ```ts + * await album.add([asset1, asset2]); + * ``` + */ + add(assets) { + const nativeAssets = Array.isArray(assets) + ? assets.map((a) => new NativeAsset(a.id)) + : new NativeAsset(assets.id); + return this.nativeAlbum.add(nativeAssets); + } + /** + * Removes assets from the album without deleting them from the library. + * This is supported only on iOS. + * + * On Android, an asset can belong to only one album. To remove it from an album, + * delete it or add it to another album. + * @platform ios + * @param assets - An array of [`Asset`](#asset) objects to remove from the album. + * @returns A promise that resolves once the assets have been removed. + * + * @example + * ```ts + * const assets = await album.getAssets(); + * await album.removeAssets(assets.slice(0, 2)); + * ``` + */ + removeAssets(assets) { + return this.nativeAlbum.removeAssets(assets.map((a) => new NativeAsset(a.id))); + } + /** + * A static function. Creates a new album with a given name and assets. + * On Android, if assets are provided and `moveAssets` is true, the assets will be moved into the new album. If false or not supported, the assets will be copied. + * + * @param name - Name of the new album. + * @param assetsRefs - List of [`Asset`](#asset) objects or file paths (file:///...) to include. + * @param moveAssets - On Android, whether to move assets into the album. Defaults to `true`. + * @returns A promise resolving to the created [`Album`](#album). + * + * @example + * ```ts + * const album = await Album.create("My Album", [asset]); + * console.log(await album.getTitle()); // "My Album" + * ``` + */ + static async create(name, assetsRefs, moveAssets) { + const nativeRefs = assetsRefs.length === 0 || typeof assetsRefs[0] === 'string' + ? assetsRefs + : assetsRefs.map((a) => new NativeAsset(a.id)); + const native = await NativeAlbum.create(name, nativeRefs, moveAssets); + return new Album(native.id); + } + /** + * A static function. Deletes multiple albums at once. + * On Android, assets are always deleted along with the album regardless of `deleteAssets`. + * @param albums - An array of [`Album`](#album) instances to delete. + * @param deleteAssets - On iOS, whether to delete the assets in the albums as well. Defaults to `false`. + * @returns A promise that resolves once the albums have been deleted. + * + * @example + * ```ts + * const album = await Album.create("My Album", [asset]); + * await Album.delete([album]); + * ``` + */ + static async delete(albums, deleteAssets) { + return NativeAlbum.delete(albums.map((a) => new NativeAlbum(a.id)), deleteAssets); + } + /** + * A static function. Retrieves an album by its title. + * @param title - The title of the album to retrieve. + * @return A promise resolving to the [`Album`](#album) if found, or `null` if not found. + * + * @example + * ```ts + * const album = await Album.get("Camera"); + * if (album) { + * console.log(await album.getTitle()); // "Camera" + * } + * ``` + */ + static async get(title) { + const native = await NativeAlbum.get(title); + return native ? new Album(native.id) : null; + } + /** + * A static function. Retrieves all albums on the device. + * @returns A promise resolving to an array of [`Album`](#album) objects. + * + * @example + * ```ts + * const albums = await Album.getAll(); + * ``` + */ + static async getAll() { + const natives = await NativeAlbum.getAll(); + return natives.map((a) => new Album(a.id)); + } +} +//# sourceMappingURL=Album.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Album.js.map b/packages/expo-media-library/build/next/js/Album.js.map new file mode 100644 index 00000000000000..8b973c6f01932c --- /dev/null +++ b/packages/expo-media-library/build/next/js/Album.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Album.js","sourceRoot":"","sources":["../../../src/next/js/Album.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,OAAO,KAAK;IAChB;;;OAGG;IACM,EAAE,CAAS;IACH,WAAW,CAAmC;IAE/D;;;OAGG;IACH,YAAY,EAAU;QACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;;;;;OAUG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,GAAG,CAAC,MAAuB;QACzB,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YACxC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1C,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,MAAe;QAC1B,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,IAAY,EACZ,UAA8B,EAC9B,UAAoB;QAEpB,MAAM,UAAU,GACd,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,OAAQ,UAAuB,CAAC,CAAC,CAAC,KAAK,QAAQ;YACxE,CAAC,CAAE,UAAuB;YAC1B,CAAC,CAAE,UAAsB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QACtE,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe,EAAE,YAAsB;QACzD,OAAO,WAAW,CAAC,MAAM,CACvB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACxC,YAAY,CACb,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAa;QAC5B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,CAAC;IAED;;;;;;;;OAQG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM;QACjB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;QAC3C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF","sourcesContent":["import { Asset } from './Asset';\nimport { NativeAsset, NativeAlbum } from '../native';\n\n/**\n * Represents a media album (collection of assets) on the device.\n *\n * An [`Album`](#album) groups together media assets (images, videos, or audio files).\n * To create a new album, use `Album.create()`.\n * To fetch an existing album, use `Album.get()`.\n */\nexport class Album {\n /**\n * Unique identifier of the album.\n * Can be used to re-instantiate an [`Album`](#album) later.\n */\n readonly id: string;\n private readonly nativeAlbum: InstanceType;\n\n /**\n * Creates an Album instance from its ID.\n * @param id - The unique identifier of the album.\n */\n constructor(id: string) {\n this.id = id;\n this.nativeAlbum = new NativeAlbum(id);\n }\n\n /**\n * Retrieves all assets contained in the album.\n * @returns A promise resolving to an array of [`Asset`](#asset) objects.\n *\n * @example\n * ```ts\n * const assets = await album.getAssets();\n * console.log(assets.length);\n * ```\n */\n async getAssets(): Promise {\n const natives = await this.nativeAlbum.getAssets();\n return natives.map((a) => new Asset(a.id));\n }\n\n /**\n * Gets the display title (name) of the album.\n * Note that album titles are not guaranteed to be unique.\n * @returns A promise resolving to the album's title string.\n *\n * @example\n * ```ts\n * const title = await album.getTitle();\n * console.log(title); // \"Camera\"\n * ```\n */\n getTitle(): Promise {\n return this.nativeAlbum.getTitle();\n }\n\n /**\n * Permanently deletes the album from the device.\n * On Android, it deletes the album and all its assets.\n * On iOS, it deletes the album but keeps the assets in the main library.\n * @returns A promise that resolves once the deletion has completed.\n * @throws An exception if the deletion fails or the album could not be found.\n *\n * @example\n * ```ts\n * await album.delete();\n * ```\n */\n delete(): Promise {\n return this.nativeAlbum.delete();\n }\n\n /**\n * Adds one or more assets to the album.\n * @param assets - The [`Asset`](#asset) or list of [`Asset`](#asset) objects to add.\n * @returns A promise that resolves once the assets have been added.\n *\n * @example\n * ```ts\n * const asset = await Asset.create(\"file:///path/to/photo.png\");\n * await album.add(asset);\n * ```\n *\n * @example\n * ```ts\n * await album.add([asset1, asset2]);\n * ```\n */\n add(assets: Asset | Asset[]): Promise {\n const nativeAssets = Array.isArray(assets)\n ? assets.map((a) => new NativeAsset(a.id))\n : new NativeAsset(assets.id);\n return this.nativeAlbum.add(nativeAssets);\n }\n\n /**\n * Removes assets from the album without deleting them from the library.\n * This is supported only on iOS.\n *\n * On Android, an asset can belong to only one album. To remove it from an album,\n * delete it or add it to another album.\n * @platform ios\n * @param assets - An array of [`Asset`](#asset) objects to remove from the album.\n * @returns A promise that resolves once the assets have been removed.\n *\n * @example\n * ```ts\n * const assets = await album.getAssets();\n * await album.removeAssets(assets.slice(0, 2));\n * ```\n */\n removeAssets(assets: Asset[]): Promise {\n return this.nativeAlbum.removeAssets(assets.map((a) => new NativeAsset(a.id)));\n }\n\n /**\n * A static function. Creates a new album with a given name and assets.\n * On Android, if assets are provided and `moveAssets` is true, the assets will be moved into the new album. If false or not supported, the assets will be copied.\n *\n * @param name - Name of the new album.\n * @param assetsRefs - List of [`Asset`](#asset) objects or file paths (file:///...) to include.\n * @param moveAssets - On Android, whether to move assets into the album. Defaults to `true`.\n * @returns A promise resolving to the created [`Album`](#album).\n *\n * @example\n * ```ts\n * const album = await Album.create(\"My Album\", [asset]);\n * console.log(await album.getTitle()); // \"My Album\"\n * ```\n */\n static async create(\n name: string,\n assetsRefs: string[] | Asset[],\n moveAssets?: boolean\n ): Promise {\n const nativeRefs =\n assetsRefs.length === 0 || typeof (assetsRefs as string[])[0] === 'string'\n ? (assetsRefs as string[])\n : (assetsRefs as Asset[]).map((a) => new NativeAsset(a.id));\n const native = await NativeAlbum.create(name, nativeRefs, moveAssets);\n return new Album(native.id);\n }\n\n /**\n * A static function. Deletes multiple albums at once.\n * On Android, assets are always deleted along with the album regardless of `deleteAssets`.\n * @param albums - An array of [`Album`](#album) instances to delete.\n * @param deleteAssets - On iOS, whether to delete the assets in the albums as well. Defaults to `false`.\n * @returns A promise that resolves once the albums have been deleted.\n *\n * @example\n * ```ts\n * const album = await Album.create(\"My Album\", [asset]);\n * await Album.delete([album]);\n * ```\n */\n static async delete(albums: Album[], deleteAssets?: boolean): Promise {\n return NativeAlbum.delete(\n albums.map((a) => new NativeAlbum(a.id)),\n deleteAssets\n );\n }\n\n /**\n * A static function. Retrieves an album by its title.\n * @param title - The title of the album to retrieve.\n * @return A promise resolving to the [`Album`](#album) if found, or `null` if not found.\n *\n * @example\n * ```ts\n * const album = await Album.get(\"Camera\");\n * if (album) {\n * console.log(await album.getTitle()); // \"Camera\"\n * }\n * ```\n */\n static async get(title: string): Promise {\n const native = await NativeAlbum.get(title);\n return native ? new Album(native.id) : null;\n }\n\n /**\n * A static function. Retrieves all albums on the device.\n * @returns A promise resolving to an array of [`Album`](#album) objects.\n *\n * @example\n * ```ts\n * const albums = await Album.getAll();\n * ```\n */\n static async getAll(): Promise {\n const natives = await NativeAlbum.getAll();\n return natives.map((a) => new Album(a.id));\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Asset.d.ts b/packages/expo-media-library/build/next/js/Asset.d.ts new file mode 100644 index 00000000000000..e438a44d4cffe1 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Asset.d.ts @@ -0,0 +1,154 @@ +import { Album } from './Album'; +import type { AssetInfo, Location, MediaSubtype, MediaType, Shape } from '../types'; +/** + * Represents a media asset in the device media library. + */ +export declare class Asset { + /** + * Asset identifier. + * Can be used to re-instantiate an [`Asset`](#asset) later. + */ + readonly id: string; + private readonly nativeAsset; + /** + * Creates an Asset instance from its ID. + * @param id - The asset identifier. On Android, this is a `content://` URI. On iOS, this is a `PHAsset` local identifier URI. + */ + constructor(id: string); + /** + * Gets the asset creation time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getCreationTime(): Promise; + /** + * Gets the asset duration. + * @returns A promise resolving to the duration in seconds, or `null` when the value is unavailable. + */ + getDuration(): Promise; + /** + * Gets the asset filename. + * @returns A promise resolving to the asset filename. + */ + getFilename(): Promise; + /** + * Gets the asset height. + * @returns A promise resolving to the asset height in pixels. + */ + getHeight(): Promise; + /** + * Gets the asset media type. + * @returns A promise resolving to the asset media type. + */ + getMediaType(): Promise; + /** + * Gets the asset modification time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getModificationTime(): Promise; + /** + * Gets the asset dimensions. + * @returns A promise resolving to the asset shape, or `null` when the value is unavailable. + */ + getShape(): Promise; + /** + * Gets the asset URI. + * @returns A promise resolving to the asset URI. + */ + getUri(): Promise; + /** + * Gets the asset width. + * @returns A promise resolving to the asset width in pixels. + */ + getWidth(): Promise; + /** + * Gets complete information about the asset. + * @returns A promise resolving to an [`AssetInfo`](#assetinfo) object. + * + * > On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, + * > which some third-party gallery apps may not use for their own favorites. + */ + getInfo(): Promise; + /** + * Gets the asset location. + * @returns A promise resolving to the asset location, or `null` when location is unavailable. + */ + getLocation(): Promise; + /** + * Gets the asset EXIF metadata. + * @returns A promise resolving to a map of EXIF tags. + */ + getExif(): Promise<{ + [key: string]: any; + }>; + /** + * Deletes the asset from the media library. + * @returns A promise resolving once the deletion has completed. + */ + delete(): Promise; + /** + * Gets albums that contain the asset. + * @returns A promise resolving to an array of [`Album`](#album) objects. + */ + getAlbums(): Promise; + /** + * Creates an asset from a local file path. + * @param filePath - Local file URI of the asset to create. + * @param album - Optional album to add the created asset to. + * @returns A promise resolving to the created [`Asset`](#asset). + */ + static create(filePath: string, album?: Album): Promise; + /** + * Deletes multiple assets from the media library. + * @param assets - Assets to delete. + * @returns A promise resolving once deletion has completed. + */ + static delete(assets: Asset[]): Promise; + /** + * Gets whether the asset is marked as a favorite. + * On iOS, this checks if the asset is part of the system "Favorites" smart album. + * On Android, this reads the `IS_FAVORITE` column from MediaStore. It requires Android 10+ + * and always returns `false` on older versions. + * @returns A promise resolving to `true` if the asset is a favorite, otherwise `false`. + */ + getFavorite(): Promise; + /** + * Marks or unmarks the asset as a favorite. + * On iOS, this adds or removes the asset from the system "Favorites" smart album. + * On Android, this updates the `IS_FAVORITE` column in MediaStore. It requires Android 10+ + * and is a no-op on older versions. + * @param isFavorite - Whether the asset should be marked as favorite. + * @returns A promise that resolves once the favorite state has been updated. + * + * > On Android, some third-party gallery apps maintain their own favorites list and may not + * > reflect changes made through this method. + */ + setFavorite(isFavorite: boolean): Promise; + /** + * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc. + * @returns A promise resolving to an array of [`MediaSubtype`](#mediasubtype) values. + * @platform ios + */ + getMediaSubtypes(): Promise; + /** + * Gets the URI of the paired video for a Live Photo asset. + * The video is extracted to a temporary file. + * @returns A promise resolving to the paired video URI, or `null` if the asset is not a Live Photo or no paired video is available. + * @platform ios + */ + getLivePhotoVideoUri(): Promise; + /** + * Gets whether the asset is stored in iCloud and not available locally. + * This does not trigger a download of the asset. + * @returns A promise resolving to `true` if the asset is stored in iCloud and unavailable locally, otherwise `false`. + * @platform ios + */ + getIsInCloud(): Promise; + /** + * Gets the EXIF display orientation of the asset. + * Only applicable for assets with media type `MediaType.IMAGE`. + * @returns A promise resolving to the EXIF orientation value, or `null` when unavailable. + * @platform ios + */ + getOrientation(): Promise; +} +//# sourceMappingURL=Asset.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Asset.d.ts.map b/packages/expo-media-library/build/next/js/Asset.d.ts.map new file mode 100644 index 00000000000000..555ea413f0fa88 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Asset.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Asset.d.ts","sourceRoot":"","sources":["../../../src/next/js/Asset.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEpF;;GAEG;AACH,qBAAa,KAAK;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;IAE/D;;;OAGG;gBACS,EAAE,EAAE,MAAM;IAKtB;;;OAGG;IACH,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIzC;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIrC;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B;;;OAGG;IACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B;;;OAGG;IACH,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAIlC;;;OAGG;IACH,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI7C;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAIjC;;;OAGG;IACH,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAIzB;;;OAGG;IACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B;;;;;;OAMG;IACH,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAI7B;;;OAGG;IACH,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAIvC;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAI1C;;;OAGG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvB;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAKnC;;;;;OAKG;WACU,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAQpE;;;;OAIG;WACU,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD;;;;;;OAMG;IACH,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B;;;;;;;;;;OAUG;IACH,WAAW,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/C;;;;OAIG;IACH,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAO3C;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAU9C;;;;;OAKG;IACH,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAOhC;;;;;OAKG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAMzC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Asset.js b/packages/expo-media-library/build/next/js/Asset.js new file mode 100644 index 00000000000000..52194686293eb1 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Asset.js @@ -0,0 +1,215 @@ +import { UnavailabilityError } from 'expo-modules-core'; +import { Platform } from 'react-native'; +import { Album } from './Album'; +import { NativeAsset, NativeAlbum } from '../native'; +/** + * Represents a media asset in the device media library. + */ +export class Asset { + /** + * Asset identifier. + * Can be used to re-instantiate an [`Asset`](#asset) later. + */ + id; + nativeAsset; + /** + * Creates an Asset instance from its ID. + * @param id - The asset identifier. On Android, this is a `content://` URI. On iOS, this is a `PHAsset` local identifier URI. + */ + constructor(id) { + this.id = id; + this.nativeAsset = new NativeAsset(id); + } + /** + * Gets the asset creation time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getCreationTime() { + return this.nativeAsset.getCreationTime(); + } + /** + * Gets the asset duration. + * @returns A promise resolving to the duration in seconds, or `null` when the value is unavailable. + */ + getDuration() { + return this.nativeAsset.getDuration(); + } + /** + * Gets the asset filename. + * @returns A promise resolving to the asset filename. + */ + getFilename() { + return this.nativeAsset.getFilename(); + } + /** + * Gets the asset height. + * @returns A promise resolving to the asset height in pixels. + */ + getHeight() { + return this.nativeAsset.getHeight(); + } + /** + * Gets the asset media type. + * @returns A promise resolving to the asset media type. + */ + getMediaType() { + return this.nativeAsset.getMediaType(); + } + /** + * Gets the asset modification time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getModificationTime() { + return this.nativeAsset.getModificationTime(); + } + /** + * Gets the asset dimensions. + * @returns A promise resolving to the asset shape, or `null` when the value is unavailable. + */ + getShape() { + return this.nativeAsset.getShape(); + } + /** + * Gets the asset URI. + * @returns A promise resolving to the asset URI. + */ + getUri() { + return this.nativeAsset.getUri(); + } + /** + * Gets the asset width. + * @returns A promise resolving to the asset width in pixels. + */ + getWidth() { + return this.nativeAsset.getWidth(); + } + /** + * Gets complete information about the asset. + * @returns A promise resolving to an [`AssetInfo`](#assetinfo) object. + * + * > On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, + * > which some third-party gallery apps may not use for their own favorites. + */ + getInfo() { + return this.nativeAsset.getInfo(); + } + /** + * Gets the asset location. + * @returns A promise resolving to the asset location, or `null` when location is unavailable. + */ + getLocation() { + return this.nativeAsset.getLocation(); + } + /** + * Gets the asset EXIF metadata. + * @returns A promise resolving to a map of EXIF tags. + */ + getExif() { + return this.nativeAsset.getExif(); + } + /** + * Deletes the asset from the media library. + * @returns A promise resolving once the deletion has completed. + */ + delete() { + return this.nativeAsset.delete(); + } + /** + * Gets albums that contain the asset. + * @returns A promise resolving to an array of [`Album`](#album) objects. + */ + async getAlbums() { + const natives = await this.nativeAsset.getAlbums(); + return natives.map((a) => new Album(a.id)); + } + /** + * Creates an asset from a local file path. + * @param filePath - Local file URI of the asset to create. + * @param album - Optional album to add the created asset to. + * @returns A promise resolving to the created [`Asset`](#asset). + */ + static async create(filePath, album) { + const native = await NativeAsset.create(filePath, album ? new NativeAlbum(album.id) : undefined); + return new Asset(native.id); + } + /** + * Deletes multiple assets from the media library. + * @param assets - Assets to delete. + * @returns A promise resolving once deletion has completed. + */ + static async delete(assets) { + return NativeAsset.delete(assets.map((a) => new NativeAsset(a.id))); + } + /** + * Gets whether the asset is marked as a favorite. + * On iOS, this checks if the asset is part of the system "Favorites" smart album. + * On Android, this reads the `IS_FAVORITE` column from MediaStore. It requires Android 10+ + * and always returns `false` on older versions. + * @returns A promise resolving to `true` if the asset is a favorite, otherwise `false`. + */ + getFavorite() { + return this.nativeAsset.getFavorite(); + } + /** + * Marks or unmarks the asset as a favorite. + * On iOS, this adds or removes the asset from the system "Favorites" smart album. + * On Android, this updates the `IS_FAVORITE` column in MediaStore. It requires Android 10+ + * and is a no-op on older versions. + * @param isFavorite - Whether the asset should be marked as favorite. + * @returns A promise that resolves once the favorite state has been updated. + * + * > On Android, some third-party gallery apps maintain their own favorites list and may not + * > reflect changes made through this method. + */ + setFavorite(isFavorite) { + return this.nativeAsset.setFavorite(isFavorite); + } + /** + * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc. + * @returns A promise resolving to an array of [`MediaSubtype`](#mediasubtype) values. + * @platform ios + */ + getMediaSubtypes() { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS'); + } + return this.nativeAsset.getMediaSubtypes(); + } + /** + * Gets the URI of the paired video for a Live Photo asset. + * The video is extracted to a temporary file. + * @returns A promise resolving to the paired video URI, or `null` if the asset is not a Live Photo or no paired video is available. + * @platform ios + */ + getLivePhotoVideoUri() { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getLivePhotoVideoUri is only available on iOS'); + } + return this.nativeAsset.getLivePhotoVideoUri(); + } + /** + * Gets whether the asset is stored in iCloud and not available locally. + * This does not trigger a download of the asset. + * @returns A promise resolving to `true` if the asset is stored in iCloud and unavailable locally, otherwise `false`. + * @platform ios + */ + getIsInCloud() { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS'); + } + return this.nativeAsset.getIsInCloud(); + } + /** + * Gets the EXIF display orientation of the asset. + * Only applicable for assets with media type `MediaType.IMAGE`. + * @returns A promise resolving to the EXIF orientation value, or `null` when unavailable. + * @platform ios + */ + getOrientation() { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS'); + } + return this.nativeAsset.getOrientation(); + } +} +//# sourceMappingURL=Asset.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Asset.js.map b/packages/expo-media-library/build/next/js/Asset.js.map new file mode 100644 index 00000000000000..c2ca8153d7c0ec --- /dev/null +++ b/packages/expo-media-library/build/next/js/Asset.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Asset.js","sourceRoot":"","sources":["../../../src/next/js/Asset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGrD;;GAEG;AACH,MAAM,OAAO,KAAK;IAChB;;;OAGG;IACM,EAAE,CAAS;IACH,WAAW,CAAmC;IAE/D;;;OAGG;IACH,YAAY,EAAU;QACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;IACzC,CAAC;IAED;;;OAGG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,WAAW,CAAC,mBAAmB,EAAE,CAAC;IAChD,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED;;;;;;OAMG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,QAAgB,EAAE,KAAa;QACjD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,MAAM,CACrC,QAAQ,EACR,KAAK,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAC9C,CAAC;QACF,OAAO,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAe;QACjC,OAAO,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;IAED;;;;;;OAMG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACxC,CAAC;IAED;;;;;;;;;;OAUG;IACH,WAAW,CAAC,UAAmB;QAC7B,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,gBAAgB;QACd,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,2CAA2C,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACH,oBAAoB;QAClB,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAC3B,cAAc,EACd,+CAA+C,CAChD,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,oBAAoB,EAAE,CAAC;IACjD,CAAC;IAED;;;;;OAKG;IACH,YAAY;QACV,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,uCAAuC,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,cAAc;QACZ,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yCAAyC,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;CACF","sourcesContent":["import { UnavailabilityError } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport { Album } from './Album';\nimport { NativeAsset, NativeAlbum } from '../native';\nimport type { AssetInfo, Location, MediaSubtype, MediaType, Shape } from '../types';\n\n/**\n * Represents a media asset in the device media library.\n */\nexport class Asset {\n /**\n * Asset identifier.\n * Can be used to re-instantiate an [`Asset`](#asset) later.\n */\n readonly id: string;\n private readonly nativeAsset: InstanceType;\n\n /**\n * Creates an Asset instance from its ID.\n * @param id - The asset identifier. On Android, this is a `content://` URI. On iOS, this is a `PHAsset` local identifier URI.\n */\n constructor(id: string) {\n this.id = id;\n this.nativeAsset = new NativeAsset(id);\n }\n\n /**\n * Gets the asset creation time.\n * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable.\n */\n getCreationTime(): Promise {\n return this.nativeAsset.getCreationTime();\n }\n\n /**\n * Gets the asset duration.\n * @returns A promise resolving to the duration in seconds, or `null` when the value is unavailable.\n */\n getDuration(): Promise {\n return this.nativeAsset.getDuration();\n }\n\n /**\n * Gets the asset filename.\n * @returns A promise resolving to the asset filename.\n */\n getFilename(): Promise {\n return this.nativeAsset.getFilename();\n }\n\n /**\n * Gets the asset height.\n * @returns A promise resolving to the asset height in pixels.\n */\n getHeight(): Promise {\n return this.nativeAsset.getHeight();\n }\n\n /**\n * Gets the asset media type.\n * @returns A promise resolving to the asset media type.\n */\n getMediaType(): Promise {\n return this.nativeAsset.getMediaType();\n }\n\n /**\n * Gets the asset modification time.\n * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable.\n */\n getModificationTime(): Promise {\n return this.nativeAsset.getModificationTime();\n }\n\n /**\n * Gets the asset dimensions.\n * @returns A promise resolving to the asset shape, or `null` when the value is unavailable.\n */\n getShape(): Promise {\n return this.nativeAsset.getShape();\n }\n\n /**\n * Gets the asset URI.\n * @returns A promise resolving to the asset URI.\n */\n getUri(): Promise {\n return this.nativeAsset.getUri();\n }\n\n /**\n * Gets the asset width.\n * @returns A promise resolving to the asset width in pixels.\n */\n getWidth(): Promise {\n return this.nativeAsset.getWidth();\n }\n\n /**\n * Gets complete information about the asset.\n * @returns A promise resolving to an [`AssetInfo`](#assetinfo) object.\n *\n * > On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column,\n * > which some third-party gallery apps may not use for their own favorites.\n */\n getInfo(): Promise {\n return this.nativeAsset.getInfo();\n }\n\n /**\n * Gets the asset location.\n * @returns A promise resolving to the asset location, or `null` when location is unavailable.\n */\n getLocation(): Promise {\n return this.nativeAsset.getLocation();\n }\n\n /**\n * Gets the asset EXIF metadata.\n * @returns A promise resolving to a map of EXIF tags.\n */\n getExif(): Promise<{ [key: string]: any }> {\n return this.nativeAsset.getExif();\n }\n\n /**\n * Deletes the asset from the media library.\n * @returns A promise resolving once the deletion has completed.\n */\n delete(): Promise {\n return this.nativeAsset.delete();\n }\n\n /**\n * Gets albums that contain the asset.\n * @returns A promise resolving to an array of [`Album`](#album) objects.\n */\n async getAlbums(): Promise {\n const natives = await this.nativeAsset.getAlbums();\n return natives.map((a) => new Album(a.id));\n }\n\n /**\n * Creates an asset from a local file path.\n * @param filePath - Local file URI of the asset to create.\n * @param album - Optional album to add the created asset to.\n * @returns A promise resolving to the created [`Asset`](#asset).\n */\n static async create(filePath: string, album?: Album): Promise {\n const native = await NativeAsset.create(\n filePath,\n album ? new NativeAlbum(album.id) : undefined\n );\n return new Asset(native.id);\n }\n\n /**\n * Deletes multiple assets from the media library.\n * @param assets - Assets to delete.\n * @returns A promise resolving once deletion has completed.\n */\n static async delete(assets: Asset[]): Promise {\n return NativeAsset.delete(assets.map((a) => new NativeAsset(a.id)));\n }\n\n /**\n * Gets whether the asset is marked as a favorite.\n * On iOS, this checks if the asset is part of the system \"Favorites\" smart album.\n * On Android, this reads the `IS_FAVORITE` column from MediaStore. It requires Android 10+\n * and always returns `false` on older versions.\n * @returns A promise resolving to `true` if the asset is a favorite, otherwise `false`.\n */\n getFavorite(): Promise {\n return this.nativeAsset.getFavorite();\n }\n\n /**\n * Marks or unmarks the asset as a favorite.\n * On iOS, this adds or removes the asset from the system \"Favorites\" smart album.\n * On Android, this updates the `IS_FAVORITE` column in MediaStore. It requires Android 10+\n * and is a no-op on older versions.\n * @param isFavorite - Whether the asset should be marked as favorite.\n * @returns A promise that resolves once the favorite state has been updated.\n *\n * > On Android, some third-party gallery apps maintain their own favorites list and may not\n * > reflect changes made through this method.\n */\n setFavorite(isFavorite: boolean): Promise {\n return this.nativeAsset.setFavorite(isFavorite);\n }\n\n /**\n * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc.\n * @returns A promise resolving to an array of [`MediaSubtype`](#mediasubtype) values.\n * @platform ios\n */\n getMediaSubtypes(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS');\n }\n return this.nativeAsset.getMediaSubtypes();\n }\n\n /**\n * Gets the URI of the paired video for a Live Photo asset.\n * The video is extracted to a temporary file.\n * @returns A promise resolving to the paired video URI, or `null` if the asset is not a Live Photo or no paired video is available.\n * @platform ios\n */\n getLivePhotoVideoUri(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError(\n 'MediaLibrary',\n 'getLivePhotoVideoUri is only available on iOS'\n );\n }\n return this.nativeAsset.getLivePhotoVideoUri();\n }\n\n /**\n * Gets whether the asset is stored in iCloud and not available locally.\n * This does not trigger a download of the asset.\n * @returns A promise resolving to `true` if the asset is stored in iCloud and unavailable locally, otherwise `false`.\n * @platform ios\n */\n getIsInCloud(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS');\n }\n return this.nativeAsset.getIsInCloud();\n }\n\n /**\n * Gets the EXIF display orientation of the asset.\n * Only applicable for assets with media type `MediaType.IMAGE`.\n * @returns A promise resolving to the EXIF orientation value, or `null` when unavailable.\n * @platform ios\n */\n getOrientation(): Promise {\n if (Platform.OS !== 'ios') {\n throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS');\n }\n return this.nativeAsset.getOrientation();\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Permissions.d.ts b/packages/expo-media-library/build/next/js/Permissions.d.ts new file mode 100644 index 00000000000000..02cac323ef412c --- /dev/null +++ b/packages/expo-media-library/build/next/js/Permissions.d.ts @@ -0,0 +1,52 @@ +import { type PermissionResponse } from 'expo'; +import type { GranularPermission, MediaTypeFilter } from '../types'; +/** + * Asks the user to grant permissions for accessing media in user's media library. + * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an + * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * + * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export declare function requestPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; +/** + * Checks user's permissions for accessing media library. + * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has + * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export declare function getPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; +/** + * Check or request permissions to access the media library. + * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. + * + * @example + * ```ts + * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ + * writeOnly: true, + * granularPermissions: ['photo'], + * }); + * ``` + */ +export declare const usePermissions: (options?: import("expo-modules-core").PermissionHookOptions<{ + writeOnly?: boolean; + granularPermissions?: GranularPermission[]; +}> | undefined) => [PermissionResponse | null, () => Promise, () => Promise]; +/** + * Allows the user to update the assets that your app has access to. + * The system modal is only displayed if the user originally allowed only `limited` access to their + * media library, otherwise this method is a no-op. + * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. + * + * @return A promise that either rejects if the method is unavailable, or resolves to `void`. + * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. + * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). + * If `hasIncrementalChanges` is `false`, the user changed their permissions. + * + * @platform android 14+ + * @platform ios + */ +export declare function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; +//# sourceMappingURL=Permissions.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Permissions.d.ts.map b/packages/expo-media-library/build/next/js/Permissions.d.ts.map new file mode 100644 index 00000000000000..e27b35b912634d --- /dev/null +++ b/packages/expo-media-library/build/next/js/Permissions.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Permissions.d.ts","sourceRoot":"","sources":["../../../src/next/js/Permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAKrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEpE;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,GAAE,OAAe,EAC1B,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,GAAE,OAAe,EAC1B,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAQ7B;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;gBAEX,OAAO;0BAAwB,kBAAkB,EAAE;oHAKjE,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5F"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Permissions.js b/packages/expo-media-library/build/next/js/Permissions.js new file mode 100644 index 00000000000000..b634d27ae7fde0 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Permissions.js @@ -0,0 +1,72 @@ +import { createPermissionHook } from 'expo'; +import { UnavailabilityError } from 'expo-modules-core'; +import { Platform } from 'react-native'; +import { NativeMediaLibraryModule } from '../native'; +/** + * Asks the user to grant permissions for accessing media in user's media library. + * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an + * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * + * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export async function requestPermissionsAsync(writeOnly = false, granularPermissions) { + if (!NativeMediaLibraryModule.requestPermissionsAsync) { + throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync'); + } + if (Platform.OS === 'android') { + return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly, granularPermissions); + } + return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly); +} +/** + * Checks user's permissions for accessing media library. + * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has + * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export async function getPermissionsAsync(writeOnly = false, granularPermissions) { + if (!NativeMediaLibraryModule.getPermissionsAsync) { + throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync'); + } + if (Platform.OS === 'android') { + return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly, granularPermissions); + } + return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly); +} +/** + * Check or request permissions to access the media library. + * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. + * + * @example + * ```ts + * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ + * writeOnly: true, + * granularPermissions: ['photo'], + * }); + * ``` + */ +export const usePermissions = createPermissionHook({ + getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions), + requestMethod: (options) => requestPermissionsAsync(options?.writeOnly, options?.granularPermissions), +}); +/** + * Allows the user to update the assets that your app has access to. + * The system modal is only displayed if the user originally allowed only `limited` access to their + * media library, otherwise this method is a no-op. + * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. + * + * @return A promise that either rejects if the method is unavailable, or resolves to `void`. + * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. + * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). + * If `hasIncrementalChanges` is `false`, the user changed their permissions. + * + * @platform android 14+ + * @platform ios + */ +export async function presentPermissionsPicker(mediaTypes) { + return await NativeMediaLibraryModule.presentPermissionsPicker(mediaTypes); +} +//# sourceMappingURL=Permissions.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Permissions.js.map b/packages/expo-media-library/build/next/js/Permissions.js.map new file mode 100644 index 00000000000000..9648de16b550e7 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Permissions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Permissions.js","sourceRoot":"","sources":["../../../src/next/js/Permissions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAA2B,MAAM,MAAM,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAGrD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,wBAAwB,CAAC,uBAAuB,EAAE,CAAC;QACtD,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,yBAAyB,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,wBAAwB,CAAC,uBAAuB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,MAAM,wBAAwB,CAAC,uBAAuB,CAAC,SAAS,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,YAAqB,KAAK,EAC1B,mBAA0C;IAE1C,IAAI,CAAC,wBAAwB,CAAC,mBAAmB,EAAE,CAAC;QAClD,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,MAAM,wBAAwB,CAAC,mBAAmB,CAAC,SAAS,EAAE,mBAAmB,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,MAAM,wBAAwB,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,CAGhD;IACA,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;IAC7F,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CACzB,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,CAAC;CAC5E,CAAC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,UAA8B;IAC3E,OAAO,MAAM,wBAAwB,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["import { createPermissionHook, type PermissionResponse } from 'expo';\nimport { UnavailabilityError } from 'expo-modules-core';\nimport { Platform } from 'react-native';\n\nimport { NativeMediaLibraryModule } from '../native';\nimport type { GranularPermission, MediaTypeFilter } from '../types';\n\n/**\n * Asks the user to grant permissions for accessing media in user's media library.\n * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`.\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an\n * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n *\n * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function requestPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!NativeMediaLibraryModule.requestPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly, granularPermissions);\n }\n return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly);\n}\n\n/**\n * Checks user's permissions for accessing media library.\n * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`.\n * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has\n * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions.\n * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object.\n */\nexport async function getPermissionsAsync(\n writeOnly: boolean = false,\n granularPermissions?: GranularPermission[]\n): Promise {\n if (!NativeMediaLibraryModule.getPermissionsAsync) {\n throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync');\n }\n if (Platform.OS === 'android') {\n return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly, granularPermissions);\n }\n return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly);\n}\n\n/**\n * Check or request permissions to access the media library.\n * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions.\n *\n * @example\n * ```ts\n * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({\n * writeOnly: true,\n * granularPermissions: ['photo'],\n * });\n * ```\n */\nexport const usePermissions = createPermissionHook<\n PermissionResponse,\n { writeOnly?: boolean; granularPermissions?: GranularPermission[] }\n>({\n getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n requestMethod: (options) =>\n requestPermissionsAsync(options?.writeOnly, options?.granularPermissions),\n});\n\n/**\n * Allows the user to update the assets that your app has access to.\n * The system modal is only displayed if the user originally allowed only `limited` access to their\n * media library, otherwise this method is a no-op.\n * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented.\n *\n * @return A promise that either rejects if the method is unavailable, or resolves to `void`.\n * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to.\n * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener).\n * If `hasIncrementalChanges` is `false`, the user changed their permissions.\n *\n * @platform android 14+\n * @platform ios\n */\nexport async function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise {\n return await NativeMediaLibraryModule.presentPermissionsPicker(mediaTypes);\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Query.d.ts b/packages/expo-media-library/build/next/js/Query.d.ts similarity index 81% rename from packages/expo-media-library/build/types/Query.d.ts rename to packages/expo-media-library/build/next/js/Query.d.ts index 71c0d31288cebe..4397e6f6036f91 100644 --- a/packages/expo-media-library/build/types/Query.d.ts +++ b/packages/expo-media-library/build/next/js/Query.d.ts @@ -1,8 +1,6 @@ import type { Album } from './Album'; -import type { Asset } from './Asset'; -import type { AssetField, AssetFieldValueMap } from './AssetField'; -import type { AssetMetadata } from './AssetMetadata'; -import type { SortDescriptor } from './SortDescriptor'; +import { Asset } from './Asset'; +import type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../types'; /** * Represents a query to fetch data from the media library. * @@ -10,44 +8,46 @@ import type { SortDescriptor } from './SortDescriptor'; * to construct complex queries. */ export declare class Query { + private readonly nativeQuery; constructor(); /** * Filters assets where the specified field is equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should equal. Each field has a specific unique type. * @returns The updated query object for chaining. */ eq(field: T, value: AssetFieldValueMap[T]): Query; /** * Filters assets where the specified field's value is in the given array of values. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - An array of values that the field should match. Each field has a specific unique type. * @returns The updated query object for chaining. */ within(field: T, value: AssetFieldValueMap[T][]): Query; /** * Filters assets where the specified field is greater than the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be greater than. * @returns The updated query object for chaining. */ gt(field: AssetField, value: number): Query; /** * Filters assets where the specified field is greater than or equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be greater than or equal to. + * @returns The updated query object for chaining. */ gte(field: AssetField, value: number): Query; /** * Filters assets where the specified field is less than the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be less than. * @returns The updated query object for chaining. */ lt(field: AssetField, value: number): Query; /** * Filters assets where the specified field is less than or equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be less than or equal to. * @returns The updated query object for chaining. */ @@ -67,6 +67,7 @@ export declare class Query { /** * Orders the results by the specified sort descriptor or asset field. * @param sortDescriptors - An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default. + * @returns The updated query object for chaining. */ orderBy(sortDescriptors: SortDescriptor | AssetField): Query; /** @@ -77,7 +78,7 @@ export declare class Query { album(album: Album): Query; /** * Executes the query and retrieves the matching assets. - * @returns A promise that resolves to an array of [Asset](#asset) objects that match the query criteria. + * @returns A promise that resolves to an array of [`Asset`](#asset) objects that match the query criteria. * * @example * ```ts @@ -96,7 +97,7 @@ export declare class Query { * Returns fields that can be read cheaply from the media store, without resolving file paths or * decoding files. * - * @returns A promise that resolves to an array of [AssetMetadata](#assetmetadata) objects that match the query criteria. + * @returns A promise that resolves to an array of [`AssetMetadata`](#assetmetadata) objects that match the query criteria. * * @example * ```ts diff --git a/packages/expo-media-library/build/next/js/Query.d.ts.map b/packages/expo-media-library/build/next/js/Query.d.ts.map new file mode 100644 index 00000000000000..fcd40dd36c7f2c --- /dev/null +++ b/packages/expo-media-library/build/next/js/Query.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../../src/next/js/Query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE9F;;;;;GAKG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmC;;IAM/D;;;;;OAKG;IACH,EAAE,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,KAAK;IAKvE;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK;IAK7E;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAK3C;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAK5C;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAK3C;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAK5C;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK;IAK3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAK7B;;;;OAIG;IACH,OAAO,CAAC,eAAe,EAAE,cAAc,GAAG,UAAU,GAAG,KAAK;IAK5D;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;IAK1B;;;;;;;;;;;;;OAaG;IACG,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAK7B;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CAG3C"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Query.js b/packages/expo-media-library/build/next/js/Query.js new file mode 100644 index 00000000000000..ecdc2dcf1a4db9 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Query.js @@ -0,0 +1,150 @@ +import { Asset } from './Asset'; +import { NativeAlbum, NativeQuery } from '../native'; +/** + * Represents a query to fetch data from the media library. + * + * A `query` implements a builder pattern, allowing you to chain multiple filtering and sorting methods + * to construct complex queries. + */ +export class Query { + nativeQuery; + constructor() { + this.nativeQuery = new NativeQuery(); + } + /** + * Filters assets where the specified field is equal to the given value. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - The value that the field should equal. Each field has a specific unique type. + * @returns The updated query object for chaining. + */ + eq(field, value) { + this.nativeQuery.eq(field, value); + return this; + } + /** + * Filters assets where the specified field's value is in the given array of values. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - An array of values that the field should match. Each field has a specific unique type. + * @returns The updated query object for chaining. + */ + within(field, value) { + this.nativeQuery.within(field, value); + return this; + } + /** + * Filters assets where the specified field is greater than the given value. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - The value that the field should be greater than. + * @returns The updated query object for chaining. + */ + gt(field, value) { + this.nativeQuery.gt(field, value); + return this; + } + /** + * Filters assets where the specified field is greater than or equal to the given value. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - The value that the field should be greater than or equal to. + * @returns The updated query object for chaining. + */ + gte(field, value) { + this.nativeQuery.gte(field, value); + return this; + } + /** + * Filters assets where the specified field is less than the given value. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - The value that the field should be less than. + * @returns The updated query object for chaining. + */ + lt(field, value) { + this.nativeQuery.lt(field, value); + return this; + } + /** + * Filters assets where the specified field is less than or equal to the given value. + * @param field - an [`AssetField`](#assetfield) to filter by. + * @param value - The value that the field should be less than or equal to. + * @returns The updated query object for chaining. + */ + lte(field, value) { + this.nativeQuery.lte(field, value); + return this; + } + /** + * Limits the number of results returned by the query. + * @param limit - The maximum number of results to return. + * @returns The updated query object for chaining. + */ + limit(limit) { + this.nativeQuery.limit(limit); + return this; + } + /** + * Skips the specified number of results. + * @param offset - The number of results to skip. + * @returns The updated query object for chaining. + */ + offset(offset) { + this.nativeQuery.offset(offset); + return this; + } + /** + * Orders the results by the specified sort descriptor or asset field. + * @param sortDescriptors - An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default. + * @returns The updated query object for chaining. + */ + orderBy(sortDescriptors) { + this.nativeQuery.orderBy(sortDescriptors); + return this; + } + /** + * Filters assets to only those contained in the specified album. + * @param album - The album to filter assets by. + * @returns The updated query object for chaining. + */ + album(album) { + this.nativeQuery.album(new NativeAlbum(album.id)); + return this; + } + /** + * Executes the query and retrieves the matching assets. + * @returns A promise that resolves to an array of [`Asset`](#asset) objects that match the query criteria. + * + * @example + * ```ts + * const assets = await new Query() + * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE) + * .lte(AssetField.HEIGHT, 1080) + * .orderBy(AssetField.CREATION_TIME) + * .limit(20) + * .exe(); + * ``` + */ + async exe() { + const natives = await this.nativeQuery.exe(); + return natives.map((a) => new Asset(a.id)); + } + /** + * Executes the query and retrieves lightweight metadata for the matching assets. + * + * Returns fields that can be read cheaply from the media store, without resolving file paths or + * decoding files. + * + * @returns A promise that resolves to an array of [`AssetMetadata`](#assetmetadata) objects that match the query criteria. + * + * @example + * ```ts + * const assets = await new Query() + * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE) + * .lte(AssetField.HEIGHT, 1080) + * .orderBy(AssetField.CREATION_TIME) + * .limit(20) + * .exeForMetadata(); + * ``` + */ + exeForMetadata() { + return this.nativeQuery.exeForMetadata(); + } +} +//# sourceMappingURL=Query.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Query.js.map b/packages/expo-media-library/build/next/js/Query.js.map new file mode 100644 index 00000000000000..f831b2e0ef97ff --- /dev/null +++ b/packages/expo-media-library/build/next/js/Query.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.js","sourceRoot":"","sources":["../../../src/next/js/Query.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGrD;;;;;GAKG;AACH,MAAM,OAAO,KAAK;IACC,WAAW,CAAmC;IAE/D;QACE,IAAI,CAAC,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;IACvC,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAuB,KAAQ,EAAE,KAA4B;QAC7D,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAuB,KAAQ,EAAE,KAA8B;QACnE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAC,KAAiB,EAAE,KAAa;QACjC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAiB,EAAE,KAAa;QAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,EAAE,CAAC,KAAiB,EAAE,KAAa;QACjC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,KAAiB,EAAE,KAAa;QAClC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAa;QACjB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,MAAc;QACnB,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,eAA4C;QAClD,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAY;QAChB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,GAAG;QACP,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;CACF","sourcesContent":["import type { Album } from './Album';\nimport { Asset } from './Asset';\nimport { NativeAlbum, NativeQuery } from '../native';\nimport type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../types';\n\n/**\n * Represents a query to fetch data from the media library.\n *\n * A `query` implements a builder pattern, allowing you to chain multiple filtering and sorting methods\n * to construct complex queries.\n */\nexport class Query {\n private readonly nativeQuery: InstanceType;\n\n constructor() {\n this.nativeQuery = new NativeQuery();\n }\n\n /**\n * Filters assets where the specified field is equal to the given value.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - The value that the field should equal. Each field has a specific unique type.\n * @returns The updated query object for chaining.\n */\n eq(field: T, value: AssetFieldValueMap[T]): Query {\n this.nativeQuery.eq(field, value);\n return this;\n }\n\n /**\n * Filters assets where the specified field's value is in the given array of values.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - An array of values that the field should match. Each field has a specific unique type.\n * @returns The updated query object for chaining.\n */\n within(field: T, value: AssetFieldValueMap[T][]): Query {\n this.nativeQuery.within(field, value);\n return this;\n }\n\n /**\n * Filters assets where the specified field is greater than the given value.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - The value that the field should be greater than.\n * @returns The updated query object for chaining.\n */\n gt(field: AssetField, value: number): Query {\n this.nativeQuery.gt(field, value);\n return this;\n }\n\n /**\n * Filters assets where the specified field is greater than or equal to the given value.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - The value that the field should be greater than or equal to.\n * @returns The updated query object for chaining.\n */\n gte(field: AssetField, value: number): Query {\n this.nativeQuery.gte(field, value);\n return this;\n }\n\n /**\n * Filters assets where the specified field is less than the given value.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - The value that the field should be less than.\n * @returns The updated query object for chaining.\n */\n lt(field: AssetField, value: number): Query {\n this.nativeQuery.lt(field, value);\n return this;\n }\n\n /**\n * Filters assets where the specified field is less than or equal to the given value.\n * @param field - an [`AssetField`](#assetfield) to filter by.\n * @param value - The value that the field should be less than or equal to.\n * @returns The updated query object for chaining.\n */\n lte(field: AssetField, value: number): Query {\n this.nativeQuery.lte(field, value);\n return this;\n }\n\n /**\n * Limits the number of results returned by the query.\n * @param limit - The maximum number of results to return.\n * @returns The updated query object for chaining.\n */\n limit(limit: number): Query {\n this.nativeQuery.limit(limit);\n return this;\n }\n\n /**\n * Skips the specified number of results.\n * @param offset - The number of results to skip.\n * @returns The updated query object for chaining.\n */\n offset(offset: number): Query {\n this.nativeQuery.offset(offset);\n return this;\n }\n\n /**\n * Orders the results by the specified sort descriptor or asset field.\n * @param sortDescriptors - An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default.\n * @returns The updated query object for chaining.\n */\n orderBy(sortDescriptors: SortDescriptor | AssetField): Query {\n this.nativeQuery.orderBy(sortDescriptors);\n return this;\n }\n\n /**\n * Filters assets to only those contained in the specified album.\n * @param album - The album to filter assets by.\n * @returns The updated query object for chaining.\n */\n album(album: Album): Query {\n this.nativeQuery.album(new NativeAlbum(album.id));\n return this;\n }\n\n /**\n * Executes the query and retrieves the matching assets.\n * @returns A promise that resolves to an array of [`Asset`](#asset) objects that match the query criteria.\n *\n * @example\n * ```ts\n * const assets = await new Query()\n * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n * .lte(AssetField.HEIGHT, 1080)\n * .orderBy(AssetField.CREATION_TIME)\n * .limit(20)\n * .exe();\n * ```\n */\n async exe(): Promise {\n const natives = await this.nativeQuery.exe();\n return natives.map((a) => new Asset(a.id));\n }\n\n /**\n * Executes the query and retrieves lightweight metadata for the matching assets.\n *\n * Returns fields that can be read cheaply from the media store, without resolving file paths or\n * decoding files.\n *\n * @returns A promise that resolves to an array of [`AssetMetadata`](#assetmetadata) objects that match the query criteria.\n *\n * @example\n * ```ts\n * const assets = await new Query()\n * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n * .lte(AssetField.HEIGHT, 1080)\n * .orderBy(AssetField.CREATION_TIME)\n * .limit(20)\n * .exeForMetadata();\n * ```\n */\n exeForMetadata(): Promise {\n return this.nativeQuery.exeForMetadata();\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Subscriptions.d.ts b/packages/expo-media-library/build/next/js/Subscriptions.d.ts new file mode 100644 index 00000000000000..e5ee50513bb7c0 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Subscriptions.d.ts @@ -0,0 +1,16 @@ +import { type EventSubscription } from 'expo-modules-core'; +import type { MediaLibraryAssetsChangeEvent } from '../types'; +/** + * Subscribes for updates in user's media library. + * @param listener A callback that is fired when any assets have been inserted or deleted from the + * library. On Android it's invoked with an empty object. On iOS it's invoked with + * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. + * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when + * you would like to unsubscribe the listener. + */ +export declare function addListener(listener: (event: MediaLibraryAssetsChangeEvent) => void): EventSubscription; +/** + * Removes all listeners. + */ +export declare function removeAllListeners(): void; +//# sourceMappingURL=Subscriptions.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Subscriptions.d.ts.map b/packages/expo-media-library/build/next/js/Subscriptions.d.ts.map new file mode 100644 index 00000000000000..eac9f34c645332 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Subscriptions.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Subscriptions.d.ts","sourceRoot":"","sources":["../../../src/next/js/Subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,UAAU,CAAC;AAE9D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,GACvD,iBAAiB,CAEnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Subscriptions.js b/packages/expo-media-library/build/next/js/Subscriptions.js new file mode 100644 index 00000000000000..9e014589796cef --- /dev/null +++ b/packages/expo-media-library/build/next/js/Subscriptions.js @@ -0,0 +1,20 @@ +import {} from 'expo-modules-core'; +import { NativeMediaLibraryModule } from '../native'; +/** + * Subscribes for updates in user's media library. + * @param listener A callback that is fired when any assets have been inserted or deleted from the + * library. On Android it's invoked with an empty object. On iOS it's invoked with + * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. + * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when + * you would like to unsubscribe the listener. + */ +export function addListener(listener) { + return NativeMediaLibraryModule.addListener('mediaLibraryDidChange', listener); +} +/** + * Removes all listeners. + */ +export function removeAllListeners() { + NativeMediaLibraryModule.removeAllListeners('mediaLibraryDidChange'); +} +//# sourceMappingURL=Subscriptions.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/Subscriptions.js.map b/packages/expo-media-library/build/next/js/Subscriptions.js.map new file mode 100644 index 00000000000000..6cc8bd5df8f677 --- /dev/null +++ b/packages/expo-media-library/build/next/js/Subscriptions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Subscriptions.js","sourceRoot":"","sources":["../../../src/next/js/Subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAGrD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,QAAwD;IAExD,OAAO,wBAAwB,CAAC,WAAW,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AACjF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,wBAAwB,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,CAAC;AACvE,CAAC","sourcesContent":["import { type EventSubscription } from 'expo-modules-core';\n\nimport { NativeMediaLibraryModule } from '../native';\nimport type { MediaLibraryAssetsChangeEvent } from '../types';\n\n/**\n * Subscribes for updates in user's media library.\n * @param listener A callback that is fired when any assets have been inserted or deleted from the\n * library. On Android it's invoked with an empty object. On iOS it's invoked with\n * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object.\n * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when\n * you would like to unsubscribe the listener.\n */\nexport function addListener(\n listener: (event: MediaLibraryAssetsChangeEvent) => void\n): EventSubscription {\n return NativeMediaLibraryModule.addListener('mediaLibraryDidChange', listener);\n}\n\n/**\n * Removes all listeners.\n */\nexport function removeAllListeners(): void {\n NativeMediaLibraryModule.removeAllListeners('mediaLibraryDidChange');\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/index.d.ts b/packages/expo-media-library/build/next/js/index.d.ts new file mode 100644 index 00000000000000..38ae5fe8f2958e --- /dev/null +++ b/packages/expo-media-library/build/next/js/index.d.ts @@ -0,0 +1,6 @@ +export { Asset } from './Asset'; +export { Album } from './Album'; +export { Query } from './Query'; +export { requestPermissionsAsync, getPermissionsAsync, usePermissions, presentPermissionsPicker, } from './Permissions'; +export { addListener, removeAllListeners } from './Subscriptions'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/index.d.ts.map b/packages/expo-media-library/build/next/js/index.d.ts.map new file mode 100644 index 00000000000000..5622b2f7a10d68 --- /dev/null +++ b/packages/expo-media-library/build/next/js/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/next/js/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/index.js b/packages/expo-media-library/build/next/js/index.js new file mode 100644 index 00000000000000..8b281fdb1661db --- /dev/null +++ b/packages/expo-media-library/build/next/js/index.js @@ -0,0 +1,6 @@ +export { Asset } from './Asset'; +export { Album } from './Album'; +export { Query } from './Query'; +export { requestPermissionsAsync, getPermissionsAsync, usePermissions, presentPermissionsPicker, } from './Permissions'; +export { addListener, removeAllListeners } from './Subscriptions'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/js/index.js.map b/packages/expo-media-library/build/next/js/index.js.map new file mode 100644 index 00000000000000..bf9f6681c71b66 --- /dev/null +++ b/packages/expo-media-library/build/next/js/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/next/js/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,wBAAwB,GACzB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { Asset } from './Asset';\nexport { Album } from './Album';\nexport { Query } from './Query';\nexport {\n requestPermissionsAsync,\n getPermissionsAsync,\n usePermissions,\n presentPermissionsPicker,\n} from './Permissions';\nexport { addListener, removeAllListeners } from './Subscriptions';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts new file mode 100644 index 00000000000000..fea809da55a72e --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts @@ -0,0 +1,6 @@ +import type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types'; +export declare const NativeMediaLibraryModule: NativeMediaLibraryModuleClass; +export declare const NativeAsset: typeof import("./types/NativeAssetClass.types").NativeAssetClass; +export declare const NativeAlbum: typeof import("./types/NativeAlbumClass.types").NativeAlbumClass; +export declare const NativeQuery: typeof import("./types/NativeQueryClass.types").NativeQueryClass; +//# sourceMappingURL=NativeMediaLibraryModule.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts.map b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts.map new file mode 100644 index 00000000000000..71412d59624a17 --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModule.d.ts","sourceRoot":"","sources":["../../../src/next/native/NativeMediaLibraryModule.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAC;AAEjG,eAAO,MAAM,wBAAwB,+BACuC,CAAC;AAC7E,eAAO,MAAM,WAAW,kEAAiC,CAAC;AAC1D,eAAO,MAAM,WAAW,kEAAiC,CAAC;AAC1D,eAAO,MAAM,WAAW,kEAAiC,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js new file mode 100644 index 00000000000000..e441a79dab78fa --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js @@ -0,0 +1,6 @@ +import { requireNativeModule } from 'expo'; +export const NativeMediaLibraryModule = requireNativeModule('ExpoMediaLibraryNext'); +export const NativeAsset = NativeMediaLibraryModule.Asset; +export const NativeAlbum = NativeMediaLibraryModule.Album; +export const NativeQuery = NativeMediaLibraryModule.Query; +//# sourceMappingURL=NativeMediaLibraryModule.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js.map b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js.map new file mode 100644 index 00000000000000..f1892640cede2f --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModule.js","sourceRoot":"","sources":["../../../src/next/native/NativeMediaLibraryModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAI3C,MAAM,CAAC,MAAM,wBAAwB,GACnC,mBAAmB,CAAgC,sBAAsB,CAAC,CAAC;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC","sourcesContent":["import { requireNativeModule } from 'expo';\n\nimport type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types';\n\nexport const NativeMediaLibraryModule =\n requireNativeModule('ExpoMediaLibraryNext');\nexport const NativeAsset = NativeMediaLibraryModule.Asset;\nexport const NativeAlbum = NativeMediaLibraryModule.Album;\nexport const NativeQuery = NativeMediaLibraryModule.Query;\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts new file mode 100644 index 00000000000000..4080c695445920 --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts @@ -0,0 +1,9 @@ +import type { NativeAlbumClass } from './types/NativeAlbumClass.types'; +import type { NativeAssetClass } from './types/NativeAssetClass.types'; +import type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types'; +import type { NativeQueryClass } from './types/NativeQueryClass.types'; +export declare const NativeMediaLibraryModule: NativeMediaLibraryModuleClass; +export declare const NativeAsset: typeof NativeAssetClass; +export declare const NativeAlbum: typeof NativeAlbumClass; +export declare const NativeQuery: typeof NativeQueryClass; +//# sourceMappingURL=NativeMediaLibraryModule.web.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts.map b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts.map new file mode 100644 index 00000000000000..b2e181169ea51d --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModule.web.d.ts","sourceRoot":"","sources":["../../../src/next/native/NativeMediaLibraryModule.web.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,6CAA6C,CAAC;AACjG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AA6KvE,eAAO,MAAM,wBAAwB,EA0BrB,6BAA6B,CAAC;AAE9C,eAAO,MAAM,WAAW,yBAAiC,CAAC;AAC1D,eAAO,MAAM,WAAW,yBAAiC,CAAC;AAC1D,eAAO,MAAM,WAAW,yBAAiC,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js new file mode 100644 index 00000000000000..8cf36019ffb986 --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js @@ -0,0 +1,176 @@ +import { PermissionStatus } from 'expo'; +import { UnavailabilityError } from 'expo-modules-core'; +const noPermissionResponse = { + status: PermissionStatus.UNDETERMINED, + canAskAgain: true, + granted: false, + expires: 'never', +}; +function unavailable(methodName) { + throw new UnavailabilityError('MediaLibrary', methodName); +} +class NativeAssetWeb { + id; + constructor(id) { + this.id = id; + } + getCreationTime() { + return unavailable('Asset.getCreationTime'); + } + getDuration() { + return unavailable('Asset.getDuration'); + } + getFilename() { + return unavailable('Asset.getFilename'); + } + getHeight() { + return unavailable('Asset.getHeight'); + } + getMediaType() { + return unavailable('Asset.getMediaType'); + } + getMediaSubtypes() { + return unavailable('Asset.getMediaSubtypes'); + } + getLivePhotoVideoUri() { + return unavailable('Asset.getLivePhotoVideoUri'); + } + getIsInCloud() { + return unavailable('Asset.getIsInCloud'); + } + getOrientation() { + return unavailable('Asset.getOrientation'); + } + getModificationTime() { + return unavailable('Asset.getModificationTime'); + } + getShape() { + return unavailable('Asset.getShape'); + } + getUri() { + return unavailable('Asset.getUri'); + } + getWidth() { + return unavailable('Asset.getWidth'); + } + getInfo() { + return unavailable('Asset.getInfo'); + } + getAlbums() { + return unavailable('Asset.getAlbums'); + } + getLocation() { + return unavailable('Asset.getLocation'); + } + getExif() { + return unavailable('Asset.getExif'); + } + delete() { + return unavailable('Asset.delete'); + } + getFavorite() { + return unavailable('Asset.getFavorite'); + } + setFavorite(_isFavorite) { + return unavailable('Asset.setFavorite'); + } + static create(_filePath, _album) { + return unavailable('Asset.create'); + } + static delete(_assets) { + return unavailable('Asset.delete'); + } +} +class NativeAlbumWeb { + id; + constructor(id) { + this.id = id; + } + getAssets() { + return unavailable('Album.getAssets'); + } + getTitle() { + return unavailable('Album.getTitle'); + } + delete() { + return unavailable('Album.delete'); + } + add(_assets) { + return unavailable('Album.add'); + } + removeAssets(_assets) { + return unavailable('Album.removeAssets'); + } + static create(_name, _assetsRefs, _moveAssets) { + return unavailable('Album.create'); + } + static delete(_albums, _deleteAssets) { + return unavailable('Album.delete'); + } + static get(_title) { + return unavailable('Album.get'); + } + static getAll() { + return unavailable('Album.getAll'); + } +} +class NativeQueryWeb { + eq(_field, _value) { + return this; + } + within(_field, _value) { + return this; + } + gt(_field, _value) { + return this; + } + gte(_field, _value) { + return this; + } + lt(_field, _value) { + return this; + } + lte(_field, _value) { + return this; + } + limit(_limit) { + return this; + } + offset(_offset) { + return this; + } + orderBy(_sortDescriptors) { + return this; + } + album(_album) { + return this; + } + exe() { + return unavailable('Query.exe'); + } + exeForMetadata() { + return unavailable('Query.exeForMetadata'); + } +} +export const NativeMediaLibraryModule = { + Asset: NativeAssetWeb, + Album: NativeAlbumWeb, + Query: NativeQueryWeb, + getPermissionsAsync(_writeOnly, _granularPermissions) { + return Promise.resolve(noPermissionResponse); + }, + requestPermissionsAsync(_writeOnly, _granularPermissions) { + return Promise.resolve(noPermissionResponse); + }, + presentPermissionsPicker(_mediaTypes) { + return unavailable('presentPermissionsPicker'); + }, + addListener(_eventName, _listener) { + return { remove() { } }; + }, + removeAllListeners(_eventName) { }, +}; +export const NativeAsset = NativeMediaLibraryModule.Asset; +export const NativeAlbum = NativeMediaLibraryModule.Album; +export const NativeQuery = NativeMediaLibraryModule.Query; +//# sourceMappingURL=NativeMediaLibraryModule.web.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js.map b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js.map new file mode 100644 index 00000000000000..98e1eacf5bc6a8 --- /dev/null +++ b/packages/expo-media-library/build/next/native/NativeMediaLibraryModule.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModule.web.js","sourceRoot":"","sources":["../../../src/next/native/NativeMediaLibraryModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAA2B,MAAM,MAAM,CAAC;AACjE,OAAO,EAA0B,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAgBhF,MAAM,oBAAoB,GAAuB;IAC/C,MAAM,EAAE,gBAAgB,CAAC,YAAY;IACrC,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF,SAAS,WAAW,CAAC,UAAkB;IACrC,MAAM,IAAI,mBAAmB,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,cAAc;IAClB,EAAE,CAAS;IAEX,YAAY,EAAU;QACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,eAAe;QACb,OAAO,WAAW,CAAC,uBAAuB,CAAC,CAAC;IAC9C,CAAC;IACD,WAAW;QACT,OAAO,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IACD,WAAW;QACT,OAAO,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IACD,SAAS;QACP,OAAO,WAAW,CAAC,iBAAiB,CAAC,CAAC;IACxC,CAAC;IACD,YAAY;QACV,OAAO,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAC3C,CAAC;IACD,gBAAgB;QACd,OAAO,WAAW,CAAC,wBAAwB,CAAC,CAAC;IAC/C,CAAC;IACD,oBAAoB;QAClB,OAAO,WAAW,CAAC,4BAA4B,CAAC,CAAC;IACnD,CAAC;IACD,YAAY;QACV,OAAO,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAC3C,CAAC;IACD,cAAc;QACZ,OAAO,WAAW,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC;IACD,mBAAmB;QACjB,OAAO,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAClD,CAAC;IACD,QAAQ;QACN,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC;IACvC,CAAC;IACD,MAAM;QACJ,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IACD,QAAQ;QACN,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC;IACvC,CAAC;IACD,OAAO;QACL,OAAO,WAAW,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IACD,SAAS;QACP,OAAO,WAAW,CAAC,iBAAiB,CAAC,CAAC;IACxC,CAAC;IACD,WAAW;QACT,OAAO,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO;QACL,OAAO,WAAW,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IACD,MAAM;QACJ,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IACD,WAAW;QACT,OAAO,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IACD,WAAW,CAAC,WAAoB;QAC9B,OAAO,WAAW,CAAC,mBAAmB,CAAC,CAAC;IAC1C,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,SAAiB,EAAE,MAAyB;QACxD,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,OAA2B;QACvC,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,cAAc;IAClB,EAAE,CAAS;IAEX,YAAY,EAAU;QACpB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,SAAS;QACP,OAAO,WAAW,CAAC,iBAAiB,CAAC,CAAC;IACxC,CAAC;IACD,QAAQ;QACN,OAAO,WAAW,CAAC,gBAAgB,CAAC,CAAC;IACvC,CAAC;IACD,MAAM;QACJ,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IACD,GAAG,CAAC,OAA8C;QAChD,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;IACD,YAAY,CAAC,OAA2B;QACtC,OAAO,WAAW,CAAC,oBAAoB,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,MAAM,CACX,KAAa,EACb,WAA0C,EAC1C,WAAqB;QAErB,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,MAAM,CAAC,OAA2B,EAAE,aAAuB;QAChE,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,MAAc;QACvB,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,CAAC,MAAM;QACX,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;IACrC,CAAC;CACF;AAED,MAAM,cAAc;IAClB,EAAE,CAAuB,MAAS,EAAE,MAA6B;QAC/D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAuB,MAAS,EAAE,MAA+B;QACrE,OAAO,IAAI,CAAC;IACd,CAAC;IACD,EAAE,CAAC,MAAkB,EAAE,MAAc;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,GAAG,CAAC,MAAkB,EAAE,MAAc;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,EAAE,CAAC,MAAkB,EAAE,MAAc;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,GAAG,CAAC,MAAkB,EAAE,MAAc;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,MAAc;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,CAAC,OAAe;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,CAAC,gBAA6C;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK,CAAC,MAAwB;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,GAAG;QACD,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC;IACD,cAAc;QACZ,OAAO,WAAW,CAAC,sBAAsB,CAAC,CAAC;IAC7C,CAAC;CACF;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,cAAc;IACrB,KAAK,EAAE,cAAc;IACrB,KAAK,EAAE,cAAc;IACrB,mBAAmB,CACjB,UAAoB,EACpB,oBAA2C;QAE3C,OAAO,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IACD,uBAAuB,CACrB,UAAoB,EACpB,oBAA2C;QAE3C,OAAO,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IACD,wBAAwB,CAAC,WAA+B;QACtD,OAAO,WAAW,CAAC,0BAA0B,CAAC,CAAC;IACjD,CAAC;IACD,WAAW,CACT,UAAmC,EACnC,SAAyD;QAEzD,OAAO,EAAE,MAAM,KAAI,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,kBAAkB,CAAC,UAAmC,IAAS,CAAC;CACrB,CAAC;AAE9C,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC;AAC1D,MAAM,CAAC,MAAM,WAAW,GAAG,wBAAwB,CAAC,KAAK,CAAC","sourcesContent":["import { PermissionStatus, type PermissionResponse } from 'expo';\nimport { type EventSubscription, UnavailabilityError } from 'expo-modules-core';\n\nimport type {\n AssetField,\n AssetFieldValueMap,\n AssetMetadata,\n GranularPermission,\n MediaTypeFilter,\n MediaLibraryAssetsChangeEvent,\n SortDescriptor,\n} from '../types';\nimport type { NativeAlbumClass } from './types/NativeAlbumClass.types';\nimport type { NativeAssetClass } from './types/NativeAssetClass.types';\nimport type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types';\nimport type { NativeQueryClass } from './types/NativeQueryClass.types';\n\nconst noPermissionResponse: PermissionResponse = {\n status: PermissionStatus.UNDETERMINED,\n canAskAgain: true,\n granted: false,\n expires: 'never',\n};\n\nfunction unavailable(methodName: string): never {\n throw new UnavailabilityError('MediaLibrary', methodName);\n}\n\nclass NativeAssetWeb implements NativeAssetClass {\n id: string;\n\n constructor(id: string) {\n this.id = id;\n }\n\n getCreationTime() {\n return unavailable('Asset.getCreationTime');\n }\n getDuration() {\n return unavailable('Asset.getDuration');\n }\n getFilename() {\n return unavailable('Asset.getFilename');\n }\n getHeight() {\n return unavailable('Asset.getHeight');\n }\n getMediaType() {\n return unavailable('Asset.getMediaType');\n }\n getMediaSubtypes() {\n return unavailable('Asset.getMediaSubtypes');\n }\n getLivePhotoVideoUri() {\n return unavailable('Asset.getLivePhotoVideoUri');\n }\n getIsInCloud() {\n return unavailable('Asset.getIsInCloud');\n }\n getOrientation() {\n return unavailable('Asset.getOrientation');\n }\n getModificationTime() {\n return unavailable('Asset.getModificationTime');\n }\n getShape() {\n return unavailable('Asset.getShape');\n }\n getUri() {\n return unavailable('Asset.getUri');\n }\n getWidth() {\n return unavailable('Asset.getWidth');\n }\n getInfo() {\n return unavailable('Asset.getInfo');\n }\n getAlbums() {\n return unavailable('Asset.getAlbums');\n }\n getLocation() {\n return unavailable('Asset.getLocation');\n }\n getExif() {\n return unavailable('Asset.getExif');\n }\n delete() {\n return unavailable('Asset.delete');\n }\n getFavorite() {\n return unavailable('Asset.getFavorite');\n }\n setFavorite(_isFavorite: boolean) {\n return unavailable('Asset.setFavorite');\n }\n\n static create(_filePath: string, _album?: NativeAlbumClass): Promise {\n return unavailable('Asset.create');\n }\n\n static delete(_assets: NativeAssetClass[]): Promise {\n return unavailable('Asset.delete');\n }\n}\n\nclass NativeAlbumWeb implements NativeAlbumClass {\n id: string;\n\n constructor(id: string) {\n this.id = id;\n }\n\n getAssets() {\n return unavailable('Album.getAssets');\n }\n getTitle() {\n return unavailable('Album.getTitle');\n }\n delete() {\n return unavailable('Album.delete');\n }\n add(_assets: NativeAssetClass | NativeAssetClass[]) {\n return unavailable('Album.add');\n }\n removeAssets(_assets: NativeAssetClass[]) {\n return unavailable('Album.removeAssets');\n }\n\n static create(\n _name: string,\n _assetsRefs: string[] | NativeAssetClass[],\n _moveAssets?: boolean\n ): Promise {\n return unavailable('Album.create');\n }\n\n static delete(_albums: NativeAlbumClass[], _deleteAssets?: boolean): Promise {\n return unavailable('Album.delete');\n }\n\n static get(_title: string): Promise {\n return unavailable('Album.get');\n }\n\n static getAll(): Promise {\n return unavailable('Album.getAll');\n }\n}\n\nclass NativeQueryWeb implements NativeQueryClass {\n eq(_field: T, _value: AssetFieldValueMap[T]) {\n return this;\n }\n within(_field: T, _value: AssetFieldValueMap[T][]) {\n return this;\n }\n gt(_field: AssetField, _value: number) {\n return this;\n }\n gte(_field: AssetField, _value: number) {\n return this;\n }\n lt(_field: AssetField, _value: number) {\n return this;\n }\n lte(_field: AssetField, _value: number) {\n return this;\n }\n limit(_limit: number) {\n return this;\n }\n offset(_offset: number) {\n return this;\n }\n orderBy(_sortDescriptors: SortDescriptor | AssetField) {\n return this;\n }\n album(_album: NativeAlbumClass) {\n return this;\n }\n exe(): Promise {\n return unavailable('Query.exe');\n }\n exeForMetadata(): Promise {\n return unavailable('Query.exeForMetadata');\n }\n}\n\nexport const NativeMediaLibraryModule = {\n Asset: NativeAssetWeb,\n Album: NativeAlbumWeb,\n Query: NativeQueryWeb,\n getPermissionsAsync(\n _writeOnly?: boolean,\n _granularPermissions?: GranularPermission[]\n ): Promise {\n return Promise.resolve(noPermissionResponse);\n },\n requestPermissionsAsync(\n _writeOnly?: boolean,\n _granularPermissions?: GranularPermission[]\n ): Promise {\n return Promise.resolve(noPermissionResponse);\n },\n presentPermissionsPicker(_mediaTypes?: MediaTypeFilter[]): Promise {\n return unavailable('presentPermissionsPicker');\n },\n addListener(\n _eventName: 'mediaLibraryDidChange',\n _listener: (event: MediaLibraryAssetsChangeEvent) => void\n ): EventSubscription {\n return { remove() {} };\n },\n removeAllListeners(_eventName: 'mediaLibraryDidChange'): void {},\n} as unknown as NativeMediaLibraryModuleClass;\n\nexport const NativeAsset = NativeMediaLibraryModule.Asset;\nexport const NativeAlbum = NativeMediaLibraryModule.Album;\nexport const NativeQuery = NativeMediaLibraryModule.Query;\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/index.d.ts b/packages/expo-media-library/build/next/native/index.d.ts new file mode 100644 index 00000000000000..2a057e2bcc7457 --- /dev/null +++ b/packages/expo-media-library/build/next/native/index.d.ts @@ -0,0 +1,2 @@ +export { NativeMediaLibraryModule, NativeAsset, NativeAlbum, NativeQuery, } from './NativeMediaLibraryModule'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/index.d.ts.map b/packages/expo-media-library/build/next/native/index.d.ts.map new file mode 100644 index 00000000000000..3ae7da529ca2f7 --- /dev/null +++ b/packages/expo-media-library/build/next/native/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/next/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,4BAA4B,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/index.js b/packages/expo-media-library/build/next/native/index.js new file mode 100644 index 00000000000000..a2d2260670aa32 --- /dev/null +++ b/packages/expo-media-library/build/next/native/index.js @@ -0,0 +1,2 @@ +export { NativeMediaLibraryModule, NativeAsset, NativeAlbum, NativeQuery, } from './NativeMediaLibraryModule'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/index.js.map b/packages/expo-media-library/build/next/native/index.js.map new file mode 100644 index 00000000000000..2c75ac21778694 --- /dev/null +++ b/packages/expo-media-library/build/next/native/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/next/native/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,WAAW,EACX,WAAW,EACX,WAAW,GACZ,MAAM,4BAA4B,CAAC","sourcesContent":["export {\n NativeMediaLibraryModule,\n NativeAsset,\n NativeAlbum,\n NativeQuery,\n} from './NativeMediaLibraryModule';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts new file mode 100644 index 00000000000000..52733148555d37 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts @@ -0,0 +1,15 @@ +import type { NativeAssetClass } from './NativeAssetClass.types'; +export declare class NativeAlbumClass { + constructor(id: string); + id: string; + getAssets(): Promise; + getTitle(): Promise; + delete(): Promise; + add(assets: NativeAssetClass | NativeAssetClass[]): Promise; + removeAssets(assets: NativeAssetClass[]): Promise; + static create(name: string, assetsRefs: string[] | NativeAssetClass[], moveAssets?: boolean): Promise; + static delete(albums: NativeAlbumClass[], deleteAssets?: boolean): Promise; + static get(title: string): Promise; + static getAll(): Promise; +} +//# sourceMappingURL=NativeAlbumClass.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts.map b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts.map new file mode 100644 index 00000000000000..083d97a294dd71 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeAlbumClass.types.d.ts","sourceRoot":"","sources":["../../../../src/next/native/types/NativeAlbumClass.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAEjE,MAAM,CAAC,OAAO,OAAO,gBAAgB;gBACvB,EAAE,EAAE,MAAM;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IACxC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAC3B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IACvB,GAAG,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IACjE,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IACvD,MAAM,CAAC,MAAM,CACX,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAAE,GAAG,gBAAgB,EAAE,EACzC,UAAU,CAAC,EAAE,OAAO,GACnB,OAAO,CAAC,gBAAgB,CAAC;IAC5B,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAChF,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAC3D,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAC7C"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js new file mode 100644 index 00000000000000..38d9cfd4efe2eb --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=NativeAlbumClass.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js.map b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js.map new file mode 100644 index 00000000000000..e37be621f9bc5e --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAlbumClass.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeAlbumClass.types.js","sourceRoot":"","sources":["../../../../src/next/native/types/NativeAlbumClass.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeAssetClass } from './NativeAssetClass.types';\n\nexport declare class NativeAlbumClass {\n constructor(id: string);\n id: string;\n getAssets(): Promise;\n getTitle(): Promise;\n delete(): Promise;\n add(assets: NativeAssetClass | NativeAssetClass[]): Promise;\n removeAssets(assets: NativeAssetClass[]): Promise;\n static create(\n name: string,\n assetsRefs: string[] | NativeAssetClass[],\n moveAssets?: boolean\n ): Promise;\n static delete(albums: NativeAlbumClass[], deleteAssets?: boolean): Promise;\n static get(title: string): Promise;\n static getAll(): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts new file mode 100644 index 00000000000000..16f695403d830b --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts @@ -0,0 +1,31 @@ +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { AssetInfo, Location, Shape, MediaSubtype, MediaType } from '../../types'; +export declare class NativeAssetClass { + constructor(id: string); + id: string; + getCreationTime(): Promise; + getDuration(): Promise; + getFilename(): Promise; + getHeight(): Promise; + getMediaType(): Promise; + getMediaSubtypes(): Promise; + getLivePhotoVideoUri(): Promise; + getIsInCloud(): Promise; + getOrientation(): Promise; + getModificationTime(): Promise; + getShape(): Promise; + getUri(): Promise; + getWidth(): Promise; + getInfo(): Promise; + getAlbums(): Promise; + getLocation(): Promise; + getExif(): Promise<{ + [key: string]: any; + }>; + delete(): Promise; + getFavorite(): Promise; + setFavorite(isFavorite: boolean): Promise; + static create(filePath: string, album?: NativeAlbumClass): Promise; + static delete(assets: NativeAssetClass[]): Promise; +} +//# sourceMappingURL=NativeAssetClass.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts.map b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts.map new file mode 100644 index 00000000000000..3d93b2d7ef83ad --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeAssetClass.types.d.ts","sourceRoot":"","sources":["../../../../src/next/native/types/NativeAssetClass.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEvF,MAAM,CAAC,OAAO,OAAO,gBAAgB;gBACvB,EAAE,EAAE,MAAM;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACzC,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACrC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAC9B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAC5B,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAClC,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAC3C,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC9C,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAChC,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACxC,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC7C,QAAQ,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IACzB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAC3B,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAC7B,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IACxC,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvC,OAAO,IAAI,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAC1C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IACvB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAC/B,WAAW,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC/C,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IACpF,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CACzD"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js new file mode 100644 index 00000000000000..af44dfe602a3c4 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=NativeAssetClass.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js.map b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js.map new file mode 100644 index 00000000000000..4f33ab42196f4e --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeAssetClass.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeAssetClass.types.js","sourceRoot":"","sources":["../../../../src/next/native/types/NativeAssetClass.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeAlbumClass } from './NativeAlbumClass.types';\nimport type { AssetInfo, Location, Shape, MediaSubtype, MediaType } from '../../types';\n\nexport declare class NativeAssetClass {\n constructor(id: string);\n id: string;\n getCreationTime(): Promise;\n getDuration(): Promise;\n getFilename(): Promise;\n getHeight(): Promise;\n getMediaType(): Promise;\n getMediaSubtypes(): Promise;\n getLivePhotoVideoUri(): Promise;\n getIsInCloud(): Promise;\n getOrientation(): Promise;\n getModificationTime(): Promise;\n getShape(): Promise;\n getUri(): Promise;\n getWidth(): Promise;\n getInfo(): Promise;\n getAlbums(): Promise;\n getLocation(): Promise;\n getExif(): Promise<{ [key: string]: any }>;\n delete(): Promise;\n getFavorite(): Promise;\n setFavorite(isFavorite: boolean): Promise;\n static create(filePath: string, album?: NativeAlbumClass): Promise;\n static delete(assets: NativeAssetClass[]): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts new file mode 100644 index 00000000000000..25a1ef5ff7075d --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts @@ -0,0 +1,16 @@ +import type { NativeModule, PermissionResponse } from 'expo'; +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { NativeAssetClass } from './NativeAssetClass.types'; +import type { NativeQueryClass } from './NativeQueryClass.types'; +import type { GranularPermission, MediaTypeFilter, MediaLibraryAssetsChangeEvent } from '../../types'; +export declare class NativeMediaLibraryModuleClass extends NativeModule<{ + mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void; +}> { + Asset: typeof NativeAssetClass; + Album: typeof NativeAlbumClass; + Query: typeof NativeQueryClass; + getPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; + requestPermissionsAsync(writeOnly?: boolean, granularPermissions?: GranularPermission[]): Promise; + presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; +} +//# sourceMappingURL=NativeMediaLibraryModuleClass.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts.map b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts.map new file mode 100644 index 00000000000000..76da0ea01b39b1 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModuleClass.types.d.ts","sourceRoot":"","sources":["../../../../src/next/native/types/NativeMediaLibraryModuleClass.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,MAAM,CAAC;AAE7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,6BAA6B,EAC9B,MAAM,aAAa,CAAC;AAErB,MAAM,CAAC,OAAO,OAAO,6BAA8B,SAAQ,YAAY,CAAC;IACtE,qBAAqB,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,IAAI,CAAC;CACvE,CAAC;IACA,KAAK,EAAE,OAAO,gBAAgB,CAAC;IAC/B,KAAK,EAAE,OAAO,gBAAgB,CAAC;IAC/B,KAAK,EAAE,OAAO,gBAAgB,CAAC;IAE/B,mBAAmB,CACjB,SAAS,CAAC,EAAE,OAAO,EACnB,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;IAC9B,uBAAuB,CACrB,SAAS,CAAC,EAAE,OAAO,EACnB,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;IAC9B,wBAAwB,CAAC,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CACxE"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js new file mode 100644 index 00000000000000..5d242d866a8265 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=NativeMediaLibraryModuleClass.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js.map b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js.map new file mode 100644 index 00000000000000..7eced70deae24b --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeMediaLibraryModuleClass.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeMediaLibraryModuleClass.types.js","sourceRoot":"","sources":["../../../../src/next/native/types/NativeMediaLibraryModuleClass.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeModule, PermissionResponse } from 'expo';\n\nimport type { NativeAlbumClass } from './NativeAlbumClass.types';\nimport type { NativeAssetClass } from './NativeAssetClass.types';\nimport type { NativeQueryClass } from './NativeQueryClass.types';\nimport type {\n GranularPermission,\n MediaTypeFilter,\n MediaLibraryAssetsChangeEvent,\n} from '../../types';\n\nexport declare class NativeMediaLibraryModuleClass extends NativeModule<{\n mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void;\n}> {\n Asset: typeof NativeAssetClass;\n Album: typeof NativeAlbumClass;\n Query: typeof NativeQueryClass;\n\n getPermissionsAsync(\n writeOnly?: boolean,\n granularPermissions?: GranularPermission[]\n ): Promise;\n requestPermissionsAsync(\n writeOnly?: boolean,\n granularPermissions?: GranularPermission[]\n ): Promise;\n presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts new file mode 100644 index 00000000000000..48dfa651123e2b --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts @@ -0,0 +1,19 @@ +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { NativeAssetClass } from './NativeAssetClass.types'; +import type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../../types'; +export declare class NativeQueryClass { + constructor(); + eq(field: T, value: AssetFieldValueMap[T]): NativeQueryClass; + within(field: T, value: AssetFieldValueMap[T][]): NativeQueryClass; + gt(field: AssetField, value: number): NativeQueryClass; + gte(field: AssetField, value: number): NativeQueryClass; + lt(field: AssetField, value: number): NativeQueryClass; + lte(field: AssetField, value: number): NativeQueryClass; + limit(limit: number): NativeQueryClass; + offset(offset: number): NativeQueryClass; + orderBy(sortDescriptors: SortDescriptor | AssetField): NativeQueryClass; + album(album: NativeAlbumClass): NativeQueryClass; + exe(): Promise; + exeForMetadata(): Promise; +} +//# sourceMappingURL=NativeQueryClass.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts.map b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts.map new file mode 100644 index 00000000000000..26fdb41eea173b --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeQueryClass.types.d.ts","sourceRoot":"","sources":["../../../../src/next/native/types/NativeQueryClass.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEjG,MAAM,CAAC,OAAO,OAAO,gBAAgB;;IAEnC,EAAE,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,gBAAgB;IAClF,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,gBAAgB;IACxF,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACtD,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACvD,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACtD,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACvD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB;IACtC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB;IACxC,OAAO,CAAC,eAAe,EAAE,cAAc,GAAG,UAAU,GAAG,gBAAgB;IACvE,KAAK,CAAC,KAAK,EAAE,gBAAgB,GAAG,gBAAgB;IAChD,GAAG,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAClC,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CAC3C"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js new file mode 100644 index 00000000000000..75e96d5fc3fa59 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=NativeQueryClass.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js.map b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js.map new file mode 100644 index 00000000000000..dd0e65e5564dd0 --- /dev/null +++ b/packages/expo-media-library/build/next/native/types/NativeQueryClass.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeQueryClass.types.js","sourceRoot":"","sources":["../../../../src/next/native/types/NativeQueryClass.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { NativeAlbumClass } from './NativeAlbumClass.types';\nimport type { NativeAssetClass } from './NativeAssetClass.types';\nimport type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../../types';\n\nexport declare class NativeQueryClass {\n constructor();\n eq(field: T, value: AssetFieldValueMap[T]): NativeQueryClass;\n within(field: T, value: AssetFieldValueMap[T][]): NativeQueryClass;\n gt(field: AssetField, value: number): NativeQueryClass;\n gte(field: AssetField, value: number): NativeQueryClass;\n lt(field: AssetField, value: number): NativeQueryClass;\n lte(field: AssetField, value: number): NativeQueryClass;\n limit(limit: number): NativeQueryClass;\n offset(offset: number): NativeQueryClass;\n orderBy(sortDescriptors: SortDescriptor | AssetField): NativeQueryClass;\n album(album: NativeAlbumClass): NativeQueryClass;\n exe(): Promise;\n exeForMetadata(): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Asset.types.d.ts b/packages/expo-media-library/build/next/types/Asset.types.d.ts new file mode 100644 index 00000000000000..2631e15d3ea273 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Asset.types.d.ts @@ -0,0 +1,62 @@ +export declare enum MediaType { + UNKNOWN = "unknown", + IMAGE = "image", + AUDIO = "audio", + VIDEO = "video" +} +/** + * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype). + * @platform ios + */ +export declare enum MediaSubtype { + DEPTH_EFFECT = "depthEffect", + HDR = "hdr", + HIGH_FRAME_RATE = "highFrameRate", + LIVE_PHOTO = "livePhoto", + PANORAMA = "panorama", + SCREENSHOT = "screenshot", + STREAM = "stream", + TIME_LAPSE = "timelapse", + SPATIAL_MEDIA = "spatialMedia", + VIDEO_CINEMATIC = "videoCinematic" +} +export type Location = { + latitude: number; + longitude: number; +}; +export type Shape = { + width: number; + height: number; +}; +export type AssetInfo = { + id: string; + filename: string; + uri: string; + mediaType: MediaType; + width: number; + height: number; + duration: number | null; + creationTime: number | null; + modificationTime: number | null; + isFavorite?: boolean; +}; +/** + * Lightweight metadata for a single asset, returned by [`Query.exeForMetadata`](#exeformetadata). + * + * Contains fields that can be read cheaply from the media store, without resolving file paths or + * decoding files. Use [`Asset`](#asset) getters when you need heavier fields such as URI or EXIF data. + * + * > On Android, `width` and `height` may be `null` when the media store does not record them. + */ +export type AssetMetadata = { + id: string; + filename: string | null; + mediaType: MediaType; + width: number | null; + height: number | null; + duration: number | null; + creationTime: number | null; + modificationTime: number | null; + isFavorite: boolean; +}; +//# sourceMappingURL=Asset.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Asset.types.d.ts.map b/packages/expo-media-library/build/next/types/Asset.types.d.ts.map new file mode 100644 index 00000000000000..b3d05c83bf6343 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Asset.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Asset.types.d.ts","sourceRoot":"","sources":["../../../src/next/types/Asset.types.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,KAAK,UAAU;CAChB;AAED;;;GAGG;AACH,oBAAY,YAAY;IACtB,YAAY,gBAAgB;IAC5B,GAAG,QAAQ;IACX,eAAe,kBAAkB;IACjC,UAAU,cAAc;IACxB,QAAQ,aAAa;IACrB,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,UAAU,cAAc;IACxB,aAAa,iBAAiB;IAC9B,eAAe,mBAAmB;CACnC;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaSubtype.js b/packages/expo-media-library/build/next/types/Asset.types.js similarity index 73% rename from packages/expo-media-library/build/types/MediaSubtype.js rename to packages/expo-media-library/build/next/types/Asset.types.js index bd2fb5fb919c41..d7e2f5cca30ed8 100644 --- a/packages/expo-media-library/build/types/MediaSubtype.js +++ b/packages/expo-media-library/build/next/types/Asset.types.js @@ -1,3 +1,10 @@ +export var MediaType; +(function (MediaType) { + MediaType["UNKNOWN"] = "unknown"; + MediaType["IMAGE"] = "image"; + MediaType["AUDIO"] = "audio"; + MediaType["VIDEO"] = "video"; +})(MediaType || (MediaType = {})); /** * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype). * @platform ios @@ -15,4 +22,4 @@ export var MediaSubtype; MediaSubtype["SPATIAL_MEDIA"] = "spatialMedia"; MediaSubtype["VIDEO_CINEMATIC"] = "videoCinematic"; })(MediaSubtype || (MediaSubtype = {})); -//# sourceMappingURL=MediaSubtype.js.map \ No newline at end of file +//# sourceMappingURL=Asset.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Asset.types.js.map b/packages/expo-media-library/build/next/types/Asset.types.js.map new file mode 100644 index 00000000000000..7227a9bc729a01 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Asset.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Asset.types.js","sourceRoot":"","sources":["../../../src/next/types/Asset.types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,gCAAmB,CAAA;IACnB,4BAAe,CAAA;IACf,4BAAe,CAAA;IACf,4BAAe,CAAA;AACjB,CAAC,EALW,SAAS,KAAT,SAAS,QAKpB;AAED;;;GAGG;AACH,MAAM,CAAN,IAAY,YAWX;AAXD,WAAY,YAAY;IACtB,4CAA4B,CAAA;IAC5B,2BAAW,CAAA;IACX,iDAAiC,CAAA;IACjC,wCAAwB,CAAA;IACxB,qCAAqB,CAAA;IACrB,yCAAyB,CAAA;IACzB,iCAAiB,CAAA;IACjB,wCAAwB,CAAA;IACxB,8CAA8B,CAAA;IAC9B,kDAAkC,CAAA;AACpC,CAAC,EAXW,YAAY,KAAZ,YAAY,QAWvB","sourcesContent":["export enum MediaType {\n UNKNOWN = 'unknown',\n IMAGE = 'image',\n AUDIO = 'audio',\n VIDEO = 'video',\n}\n\n/**\n * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype).\n * @platform ios\n */\nexport enum MediaSubtype {\n DEPTH_EFFECT = 'depthEffect',\n HDR = 'hdr',\n HIGH_FRAME_RATE = 'highFrameRate',\n LIVE_PHOTO = 'livePhoto',\n PANORAMA = 'panorama',\n SCREENSHOT = 'screenshot',\n STREAM = 'stream',\n TIME_LAPSE = 'timelapse',\n SPATIAL_MEDIA = 'spatialMedia',\n VIDEO_CINEMATIC = 'videoCinematic',\n}\n\nexport type Location = {\n latitude: number;\n longitude: number;\n};\n\nexport type Shape = {\n width: number;\n height: number;\n};\n\nexport type AssetInfo = {\n id: string;\n filename: string;\n uri: string;\n mediaType: MediaType;\n width: number;\n height: number;\n duration: number | null;\n creationTime: number | null;\n modificationTime: number | null;\n isFavorite?: boolean;\n};\n\n/**\n * Lightweight metadata for a single asset, returned by [`Query.exeForMetadata`](#exeformetadata).\n *\n * Contains fields that can be read cheaply from the media store, without resolving file paths or\n * decoding files. Use [`Asset`](#asset) getters when you need heavier fields such as URI or EXIF data.\n *\n * > On Android, `width` and `height` may be `null` when the media store does not record them.\n */\nexport type AssetMetadata = {\n id: string;\n filename: string | null;\n mediaType: MediaType;\n width: number | null;\n height: number | null;\n duration: number | null;\n creationTime: number | null;\n modificationTime: number | null;\n isFavorite: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Permissions.types.d.ts b/packages/expo-media-library/build/next/types/Permissions.types.d.ts new file mode 100644 index 00000000000000..12dad30f1a675c --- /dev/null +++ b/packages/expo-media-library/build/next/types/Permissions.types.d.ts @@ -0,0 +1,4 @@ +export type GranularPermission = 'audio' | 'photo' | 'video'; +export type MediaTypeFilter = 'photo' | 'video'; +export { PermissionStatus, type PermissionExpiration, type PermissionHookOptions, type PermissionResponse, } from 'expo'; +//# sourceMappingURL=Permissions.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Permissions.types.d.ts.map b/packages/expo-media-library/build/next/types/Permissions.types.d.ts.map new file mode 100644 index 00000000000000..bcc5ce46bdc402 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Permissions.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Permissions.types.d.ts","sourceRoot":"","sources":["../../../src/next/types/Permissions.types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhD,OAAO,EACL,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,GACxB,MAAM,MAAM,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Permissions.types.js b/packages/expo-media-library/build/next/types/Permissions.types.js new file mode 100644 index 00000000000000..1a7918314ea160 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Permissions.types.js @@ -0,0 +1,2 @@ +export { PermissionStatus, } from 'expo'; +//# sourceMappingURL=Permissions.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Permissions.types.js.map b/packages/expo-media-library/build/next/types/Permissions.types.js.map new file mode 100644 index 00000000000000..f122a2c13d7576 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Permissions.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Permissions.types.js","sourceRoot":"","sources":["../../../src/next/types/Permissions.types.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,GAIjB,MAAM,MAAM,CAAC","sourcesContent":["export type GranularPermission = 'audio' | 'photo' | 'video';\n\nexport type MediaTypeFilter = 'photo' | 'video';\n\nexport {\n PermissionStatus,\n type PermissionExpiration,\n type PermissionHookOptions,\n type PermissionResponse,\n} from 'expo';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetField.d.ts b/packages/expo-media-library/build/next/types/Query.types.d.ts similarity index 76% rename from packages/expo-media-library/build/types/AssetField.d.ts rename to packages/expo-media-library/build/next/types/Query.types.d.ts index 7281333d329e0f..c968b3640f33dd 100644 --- a/packages/expo-media-library/build/types/AssetField.d.ts +++ b/packages/expo-media-library/build/next/types/Query.types.d.ts @@ -1,4 +1,4 @@ -import type { MediaType } from './MediaType'; +import type { MediaType } from './Asset.types'; export declare enum AssetField { CREATION_TIME = "creationTime", MODIFICATION_TIME = "modificationTime", @@ -17,4 +17,8 @@ export type AssetFieldValueMap = { [AssetField.DURATION]: number; [AssetField.IS_FAVORITE]: boolean; }; -//# sourceMappingURL=AssetField.d.ts.map \ No newline at end of file +export type SortDescriptor = { + key: AssetField; + ascending?: boolean; +}; +//# sourceMappingURL=Query.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Query.types.d.ts.map b/packages/expo-media-library/build/next/types/Query.types.d.ts.map new file mode 100644 index 00000000000000..0095fb70955de4 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Query.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.types.d.ts","sourceRoot":"","sources":["../../../src/next/types/Query.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,oBAAY,UAAU;IACpB,aAAa,iBAAiB;IAC9B,iBAAiB,qBAAqB;IACtC,UAAU,cAAc;IACxB,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,WAAW,eAAe;CAC3B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;IACnC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC9B,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetField.js b/packages/expo-media-library/build/next/types/Query.types.js similarity index 91% rename from packages/expo-media-library/build/types/AssetField.js rename to packages/expo-media-library/build/next/types/Query.types.js index b2013e1956f367..9aab0601012668 100644 --- a/packages/expo-media-library/build/types/AssetField.js +++ b/packages/expo-media-library/build/next/types/Query.types.js @@ -8,4 +8,4 @@ export var AssetField; AssetField["DURATION"] = "duration"; AssetField["IS_FAVORITE"] = "isFavorite"; })(AssetField || (AssetField = {})); -//# sourceMappingURL=AssetField.js.map \ No newline at end of file +//# sourceMappingURL=Query.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Query.types.js.map b/packages/expo-media-library/build/next/types/Query.types.js.map new file mode 100644 index 00000000000000..0052f00fbe4f12 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Query.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Query.types.js","sourceRoot":"","sources":["../../../src/next/types/Query.types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IACpB,4CAA8B,CAAA;IAC9B,oDAAsC,CAAA;IACtC,sCAAwB,CAAA;IACxB,6BAAe,CAAA;IACf,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;IACrB,wCAA0B,CAAA;AAC5B,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB","sourcesContent":["import type { MediaType } from './Asset.types';\n\nexport enum AssetField {\n CREATION_TIME = 'creationTime',\n MODIFICATION_TIME = 'modificationTime',\n MEDIA_TYPE = 'mediaType',\n WIDTH = 'width',\n HEIGHT = 'height',\n DURATION = 'duration',\n IS_FAVORITE = 'isFavorite',\n}\n\nexport type AssetFieldValueMap = {\n [AssetField.CREATION_TIME]: number;\n [AssetField.MODIFICATION_TIME]: number;\n [AssetField.MEDIA_TYPE]: MediaType;\n [AssetField.WIDTH]: number;\n [AssetField.HEIGHT]: number;\n [AssetField.DURATION]: number;\n [AssetField.IS_FAVORITE]: boolean;\n};\n\nexport type SortDescriptor = {\n key: AssetField;\n ascending?: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts b/packages/expo-media-library/build/next/types/Subscriptions.types.d.ts similarity index 89% rename from packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts rename to packages/expo-media-library/build/next/types/Subscriptions.types.d.ts index 5e2b630a569bb8..5dcb10c05987a4 100644 --- a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts +++ b/packages/expo-media-library/build/next/types/Subscriptions.types.d.ts @@ -1,3 +1,4 @@ +export { type EventSubscription, type EventSubscription as Subscription } from 'expo-modules-core'; /** * An event emitted when assets in the media library change. */ @@ -29,4 +30,4 @@ export type MediaLibraryAssetsChangeEvent = { */ updatedAssets?: string[]; }; -//# sourceMappingURL=MediaLibraryAssetsChangeEvent.d.ts.map \ No newline at end of file +//# sourceMappingURL=Subscriptions.types.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Subscriptions.types.d.ts.map b/packages/expo-media-library/build/next/types/Subscriptions.types.d.ts.map new file mode 100644 index 00000000000000..c88edf2daf42f9 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Subscriptions.types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Subscriptions.types.d.ts","sourceRoot":"","sources":["../../../src/next/types/Subscriptions.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,IAAI,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEnG;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;;;;;OAMG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Subscriptions.types.js b/packages/expo-media-library/build/next/types/Subscriptions.types.js new file mode 100644 index 00000000000000..e69638bf9e0e82 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Subscriptions.types.js @@ -0,0 +1,2 @@ +export {} from 'expo-modules-core'; +//# sourceMappingURL=Subscriptions.types.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/Subscriptions.types.js.map b/packages/expo-media-library/build/next/types/Subscriptions.types.js.map new file mode 100644 index 00000000000000..623fa6871d0c31 --- /dev/null +++ b/packages/expo-media-library/build/next/types/Subscriptions.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Subscriptions.types.js","sourceRoot":"","sources":["../../../src/next/types/Subscriptions.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkE,MAAM,mBAAmB,CAAC","sourcesContent":["export { type EventSubscription, type EventSubscription as Subscription } from 'expo-modules-core';\n\n/**\n * An event emitted when assets in the media library change.\n */\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes can be described as incremental changes.\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload.\n * On Android this is always `false` because the platform does not provide incremental change details.\n */\n hasIncrementalChanges: boolean;\n /**\n * Array of asset IDs (`ph://` URIs) that have been inserted to the library.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n insertedAssets?: string[];\n /**\n * Array of asset IDs (`ph://` URIs) that have been deleted from the library.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n deletedAssets?: string[];\n /**\n * Array of asset IDs (`ph://` URIs) that have been updated.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n updatedAssets?: string[];\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/index.d.ts b/packages/expo-media-library/build/next/types/index.d.ts new file mode 100644 index 00000000000000..3985e3a9fa1e83 --- /dev/null +++ b/packages/expo-media-library/build/next/types/index.d.ts @@ -0,0 +1,5 @@ +export * from './Asset.types'; +export * from './Query.types'; +export * from './Permissions.types'; +export * from './Subscriptions.types'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/index.d.ts.map b/packages/expo-media-library/build/next/types/index.d.ts.map new file mode 100644 index 00000000000000..5147eea30ed603 --- /dev/null +++ b/packages/expo-media-library/build/next/types/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/next/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/index.js b/packages/expo-media-library/build/next/types/index.js new file mode 100644 index 00000000000000..f41039fd522418 --- /dev/null +++ b/packages/expo-media-library/build/next/types/index.js @@ -0,0 +1,5 @@ +export * from './Asset.types'; +export * from './Query.types'; +export * from './Permissions.types'; +export * from './Subscriptions.types'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/next/types/index.js.map b/packages/expo-media-library/build/next/types/index.js.map new file mode 100644 index 00000000000000..3ea3aaacf46116 --- /dev/null +++ b/packages/expo-media-library/build/next/types/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/next/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC","sourcesContent":["export * from './Asset.types';\nexport * from './Query.types';\nexport * from './Permissions.types';\nexport * from './Subscriptions.types';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Album.d.ts.map b/packages/expo-media-library/build/types/Album.d.ts.map deleted file mode 100644 index 570b92d02873c5..00000000000000 --- a/packages/expo-media-library/build/types/Album.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Album.d.ts","sourceRoot":"","sources":["../../src/types/Album.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;OAGG;gBACS,EAAE,EAAE,MAAM;IAEtB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;;;;;;OASG;IACH,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAE7B;;;;;;;;;;OAUG;IACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAE3B;;;;;;;;;;;OAWG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAEvB;;;;;;;;;;;;;;;OAeG;IACH,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAE3C;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAE5C;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC;IAEjG;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAErE;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAEhD;;;;;;;;OAQG;IACH,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;CAClC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Album.js b/packages/expo-media-library/build/types/Album.js deleted file mode 100644 index 33c72f0ca9d31d..00000000000000 --- a/packages/expo-media-library/build/types/Album.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=Album.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Album.js.map b/packages/expo-media-library/build/types/Album.js.map deleted file mode 100644 index 7b0996f88f6a65..00000000000000 --- a/packages/expo-media-library/build/types/Album.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Album.js","sourceRoot":"","sources":["../../src/types/Album.ts"],"names":[],"mappings":"","sourcesContent":["import type { Asset } from './Asset';\n\n/**\n * Represents a media album (collection of assets) on the device.\n *\n * An [Album](#album) groups together media assets (images, videos, or audio files).\n * To create a new album, use [Album.create](#albumcreate).\n * To fetch an existing album, use [Album.get](#albumget).\n */\nexport declare class Album {\n /**\n * Reinitialize an instance of an album with a given ID.\n * @param id - The unique identifier of the album.\n */\n constructor(id: string);\n\n /**\n * Unique identifier of the album.\n * Can be used to re-instantiate an [Album](#album) later.\n */\n id: string;\n\n /**\n * Retrieves all assets contained in the album.\n * @returns A promise resolving to an array of [Asset](#asset) objects.\n *\n * @example\n * ```ts\n * const assets = await album.getAssets();\n * console.log(assets.length);\n * ```\n */\n getAssets(): Promise;\n\n /**\n * Gets the display title (name) of the album.\n * Note that album titles are not guaranteed to be unique.\n * @returns A promise resolving to the album’s title string.\n *\n * @example\n * ```ts\n * const title = await album.getTitle();\n * console.log(title); // \"Camera\"\n * ```\n */\n getTitle(): Promise;\n\n /**\n * Permanently deletes the album from the device.\n * On Android, it deletes the album and all its assets.\n * On iOS, it deletes the album but keeps the assets in the main library.\n * @returns A promise that resolves once the deletion has completed.\n * @throws An exception if the deletion fails or the album could not be found.\n *\n * @example\n * ```ts\n * await album.delete();\n * ```\n */\n delete(): Promise;\n\n /**\n * Adds one or more assets to the album.\n * @param assets - The [Asset](#asset) or list of [Asset](#asset) objects to add.\n * @returns A promise that resolves once the assets have been added.\n *\n * @example\n * ```ts\n * const asset = await Asset.create(\"file:///path/to/photo.png\");\n * await album.add(asset);\n * ```\n *\n * @example\n * ```ts\n * await album.add([asset1, asset2]);\n * ```\n */\n add(assets: Asset | Asset[]): Promise;\n\n /**\n * Removes assets from the album without deleting them from the library.\n * This is supported only on iOS.\n *\n * On Android, an asset can belong to only one album. To remove it from an album,\n * delete it or add it to another album.\n * @platform ios\n * @param assets - An array of [Asset](#asset) objects to remove from the album.\n * @returns A promise that resolves once the assets have been removed.\n *\n * @example\n * ```ts\n * const assets = await album.getAssets();\n * await album.removeAssets(assets.slice(0, 2));\n * ```\n */\n removeAssets(assets: Asset[]): Promise;\n\n /**\n * A static function. Creates a new album with a given name and assets.\n * On Android, if assets are provided and `moveAssets` is true, the assets will be moved into the new album. If false or not supported, the assets will be copied.\n *\n * @param name - Name of the new album.\n * @param assetsRefs - List of [Asset](#asset) objects or file paths (file:///...) to include.\n * @param moveAssets - On Android, whether to move assets into the album. Defaults to `true`.\n * @returns A promise resolving to the created [Album](#album).\n *\n * @example\n * ```ts\n * const album = await Album.create(\"My Album\", [asset]);\n * console.log(await album.getTitle()); // \"My Album\"\n * ```\n */\n static create(name: string, assetsRefs: string[] | Asset[], moveAssets?: boolean): Promise;\n\n /**\n * A static function. Deletes multiple albums at once.\n * On Android, assets are always deleted along with the album regardless of `deleteAssets`.\n * @param albums - An array of [Album](#album) instances to delete.\n * @param deleteAssets - On iOS, whether to delete the assets in the albums as well. Defaults to `false`.\n * @returns A promise that resolves once the albums have been deleted.\n *\n * @example\n * ```ts\n * const album = await Album.create(\"My Album\", [asset]);\n * await Album.delete([album]);\n * ```\n */\n static delete(albums: Album[], deleteAssets?: boolean): Promise;\n\n /**\n * A static function. Retrieves an album by its title.\n * @param title - The title of the album to retrieve.\n * @return A promise resolving to the [Album](#album) if found, or `null` if not found.\n *\n * @example\n * ```ts\n * const album = await Album.get(\"Camera\");\n * if (album) {\n * console.log(await album.getTitle()); // \"Camera\"\n * }\n * ```\n */\n static get(title: string): Promise;\n\n /**\n * A static function. Retrieves all albums on the device.\n * @returns A promise resolving to an array of [Album](#album) objects.\n *\n * @example\n * ```ts\n * const albums = await Album.getAll();\n * ```\n */\n static getAll(): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Asset.d.ts b/packages/expo-media-library/build/types/Asset.d.ts deleted file mode 100644 index 17d410817ac481..00000000000000 --- a/packages/expo-media-library/build/types/Asset.d.ts +++ /dev/null @@ -1,201 +0,0 @@ -import type { Album } from './Album'; -import type { AssetInfo } from './AssetInfo'; -import type { Location } from './Location'; -import type { MediaSubtype } from './MediaSubtype'; -import type { MediaType } from './MediaType'; -import type { Shape } from './Shape'; -/** - * Represents a single media asset on the device (image, video, or audio). - * - * An [Asset](#asset) instance corresponds to an entry in the device's media store. - * It exposes metadata (such as filename, dimensions, or creation time) and utility methods (like deleting). - * - * To create a new asset, use [Asset.create](#assetcreate), if you already have an asset ID, you can instantiate it directly using the constructor. - */ -export declare class Asset { - /** - * Reinitialize an instance of an asset with a given ID. - * @param id - For Android, it is a `contentUri` (content://media/external/images/media/12345) and for iOS, it is `PHAsset` localIdentifier URI. - */ - constructor(id: string); - /** - * ID of the asset. - * Can be used to re-instantiate an [Asset](#asset) later. - * For android it is a contentUri and PHAsset localIdentifier URI for iOS. - */ - id: string; - /** - * Gets the creation time of the asset. - * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable. - * @throws An exception if the asset could not be found. - */ - getCreationTime(): Promise; - /** - * Gets the duration of the asset. - * Applies only to assets with media type [MediaType.audio](#mediatype) or [MediaType.video](#mediatype). - * For other media types, it returns `null`. - * @returns A promise resolving to the duration in milliseconds, or `null` if not applicable. - * @throws An exception if the asset could not be found. - */ - getDuration(): Promise; - /** - * Gets the filename of the asset, including its extension. - * @returns A promise resolving to the filename string. - * @throws An exception if the asset could not be found. - */ - getFilename(): Promise; - /** - * Gets the height of the asset in pixels. - * Only applicable for image and video assets. - * @returns A promise resolving to the height in pixels. - * @throws An exception if the filename cannot be found. - */ - getHeight(): Promise; - /** - * Gets the media type of the asset (image, video, audio or unknown). - * @returns A promise resolving to a [MediaType](#mediatype) enum value. - * @throws An exception if the asset could not be found. - */ - getMediaType(): Promise; - /** - * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc. - * @returns A promise resolving to an array of [MediaSubtype](#mediasubtype) strings. Returns an empty array if no subtypes apply. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getMediaSubtypes(): Promise; - /** - * Gets the URI of the paired video for a Live Photo asset. - * The video is extracted to a temporary file. - * @returns A promise resolving to a `file://` URI string, or `null` if the asset is not a Live Photo. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getLivePhotoVideoUri(): Promise; - /** - * Gets whether the asset is stored in iCloud and not available locally. - * This does not trigger a download of the asset. - * @returns A promise resolving to `true` if the asset is stored in iCloud and not available locally. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getIsInCloud(): Promise; - /** - * Gets the EXIF display orientation of the asset. - * Only applicable for assets with media type [MediaType.image](#mediatype). - * @returns A promise resolving to a value between 1 and 8 as defined by the [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html), or `null` if unavailable. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getOrientation(): Promise; - /** - * Gets the last modification time of the asset. - * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable. - * @throws An exception if the asset could not be found. - */ - getModificationTime(): Promise; - /** - * Gets the shape (width and height) of the asset. - * @returns A promise resolving to the [Shape](#shape) object, or `null` if any dimension is unavailable. - * @throws An exception if the asset could not be found. - */ - getShape(): Promise; - /** - * Gets the URI pointing to the asset’s location in the system. - * Example, for Android: `file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg`. - * @returns A promise resolving to the string URI. - * @throws An exception if the asset could not be found. - */ - getUri(): Promise; - /** - * Gets the width of the asset in pixels. - * Only applicable for image and video assets. - * @returns A promise resolving to the width in pixels. - * @throws An exception if the asset could not be found. - */ - getWidth(): Promise; - /** - * Gets detailed information about the asset. - * @returns A promise resolving to an [AssetInfo](#assetinfo) - * @throws An exception if the asset could not be found. - * - * > **Note:** On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, which some third-party gallery apps may not use for their own favorites. - */ - getInfo(): Promise; - /** - * Gets the albums containing this asset. - * On Android, an asset is typically associated with a single album. - * On iOS, an asset may belong to multiple albums. - * @returns A promise resolving to an array of [Album](#album) objects. - * @throws An exception if the asset could not be found. - * - * @example - * ```ts - * const albums = await asset.getAlbums(); - * console.log(albums.length); - * ``` - */ - getAlbums(): Promise; - /** - * Gets the location of the asset. - * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata. - * @returns A promise resolving to the [Location](#location) object or `null` if the location data is unavailable. - * @throws An exception if the asset could not be found, or if the permission is not granted on Android. - */ - getLocation(): Promise; - /** - * Gets the exif data of the [MediaType.image](#mediatype) asset. - * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata. - * @returns A promise resolving to the exif data object or an empty object if the exif data is unavailable. - * @throws An exception if the asset could not be found. - */ - getExif(): Promise<{ - [key: string]: any; - }>; - /** - * Deletes the asset from the device’s media store. - * @returns A promise that resolves once the deletion has completed. - * - * @example - * ```ts - * await asset.delete(); - * ``` - */ - delete(): Promise; - /** - * Gets whether the asset is marked as a favorite. - * On iOS, this checks if the asset is part of the system "Favorites" smart album. - * On Android, this reads the `IS_FAVORITE` column from MediaStore (requires Android 10+; always returns `false` on older versions). - * @returns A promise resolving to `true` if the asset is a favorite, or `false` otherwise. - * - * @example - * ```ts - * const isFavorite = await asset.getFavorite(); - * console.log(isFavorite); // true or false - * ``` - */ - getFavorite(): Promise; - /** - * Marks or unmarks the asset as a favorite. - * On iOS, this adds or removes the asset from the system "Favorites" smart album. - * On Android, this updates the `IS_FAVORITE` column in MediaStore (requires Android 10+; no-op on older versions). - * @param isFavorite Whether the asset should be marked as favorite. - * @returns A promise that resolves once the operation has completed. - * - * > **Note:** On Android, some third-party gallery apps maintain their own favorites list and may not reflect changes made through this method. - * - * @example - * ```ts - * await asset.setFavorite(true); - * ``` - */ - setFavorite(isFavorite: boolean): Promise; - static create(filePath: string, album?: Album): Promise; - /** - * A static function. Deletes multiple assets from the device's media store. - * @param assets - An array of [Asset](#asset) instances to delete. - * @returns A promise that resolves once the deletion has completed. - */ - static delete(assets: Asset[]): Promise; -} -//# sourceMappingURL=Asset.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Asset.d.ts.map b/packages/expo-media-library/build/types/Asset.d.ts.map deleted file mode 100644 index 74148ca533422b..00000000000000 --- a/packages/expo-media-library/build/types/Asset.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Asset.d.ts","sourceRoot":"","sources":["../../src/types/Asset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;IACxB;;;OAGG;gBACS,EAAE,EAAE,MAAM;IAEtB;;;;OAIG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;;;OAIG;IACH,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAEzC;;;;;;OAMG;IACH,WAAW,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAErC;;;;OAIG;IACH,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAE9B;;;;;OAKG;IACH,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAE5B;;;;OAIG;IACH,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAElC;;;;;OAKG;IACH,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAE3C;;;;;;OAMG;IACH,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAE9C;;;;;;OAMG;IACH,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAEhC;;;;;;OAMG;IACH,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAExC;;;;OAIG;IACH,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAE7C;;;;OAIG;IACH,QAAQ,IAAI,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAEjC;;;;;OAKG;IACH,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAE3B;;;;;;OAMG;IACH,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;IAE7B;;;;;;;;;;;;OAYG;IACH,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAE7B;;;;;OAKG;IACH,WAAW,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAEvC;;;;;OAKG;IACH,OAAO,IAAI,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IAE1C;;;;;;;;OAQG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAEvB;;;;;;;;;;;OAWG;IACH,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAE/B;;;;;;;;;;;;;OAaG;IACH,WAAW,CAAC,UAAU,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB/C,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAE9D;;;;OAIG;IACH,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAC9C"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Asset.js b/packages/expo-media-library/build/types/Asset.js deleted file mode 100644 index 1511247062667d..00000000000000 --- a/packages/expo-media-library/build/types/Asset.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=Asset.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Asset.js.map b/packages/expo-media-library/build/types/Asset.js.map deleted file mode 100644 index bef34702ba191b..00000000000000 --- a/packages/expo-media-library/build/types/Asset.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Asset.js","sourceRoot":"","sources":["../../src/types/Asset.ts"],"names":[],"mappings":"","sourcesContent":["import type { Album } from './Album';\nimport type { AssetInfo } from './AssetInfo';\nimport type { Location } from './Location';\nimport type { MediaSubtype } from './MediaSubtype';\nimport type { MediaType } from './MediaType';\nimport type { Shape } from './Shape';\n\n/**\n * Represents a single media asset on the device (image, video, or audio).\n *\n * An [Asset](#asset) instance corresponds to an entry in the device's media store.\n * It exposes metadata (such as filename, dimensions, or creation time) and utility methods (like deleting).\n *\n * To create a new asset, use [Asset.create](#assetcreate), if you already have an asset ID, you can instantiate it directly using the constructor.\n */\nexport declare class Asset {\n /**\n * Reinitialize an instance of an asset with a given ID.\n * @param id - For Android, it is a `contentUri` (content://media/external/images/media/12345) and for iOS, it is `PHAsset` localIdentifier URI.\n */\n constructor(id: string);\n\n /**\n * ID of the asset.\n * Can be used to re-instantiate an [Asset](#asset) later.\n * For android it is a contentUri and PHAsset localIdentifier URI for iOS.\n */\n id: string;\n\n /**\n * Gets the creation time of the asset.\n * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable.\n * @throws An exception if the asset could not be found.\n */\n getCreationTime(): Promise;\n\n /**\n * Gets the duration of the asset.\n * Applies only to assets with media type [MediaType.audio](#mediatype) or [MediaType.video](#mediatype).\n * For other media types, it returns `null`.\n * @returns A promise resolving to the duration in milliseconds, or `null` if not applicable.\n * @throws An exception if the asset could not be found.\n */\n getDuration(): Promise;\n\n /**\n * Gets the filename of the asset, including its extension.\n * @returns A promise resolving to the filename string.\n * @throws An exception if the asset could not be found.\n */\n getFilename(): Promise;\n\n /**\n * Gets the height of the asset in pixels.\n * Only applicable for image and video assets.\n * @returns A promise resolving to the height in pixels.\n * @throws An exception if the filename cannot be found.\n */\n getHeight(): Promise;\n\n /**\n * Gets the media type of the asset (image, video, audio or unknown).\n * @returns A promise resolving to a [MediaType](#mediatype) enum value.\n * @throws An exception if the asset could not be found.\n */\n getMediaType(): Promise;\n\n /**\n * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc.\n * @returns A promise resolving to an array of [MediaSubtype](#mediasubtype) strings. Returns an empty array if no subtypes apply.\n * @throws An exception if the asset could not be found.\n * @platform ios\n */\n getMediaSubtypes(): Promise;\n\n /**\n * Gets the URI of the paired video for a Live Photo asset.\n * The video is extracted to a temporary file.\n * @returns A promise resolving to a `file://` URI string, or `null` if the asset is not a Live Photo.\n * @throws An exception if the asset could not be found.\n * @platform ios\n */\n getLivePhotoVideoUri(): Promise;\n\n /**\n * Gets whether the asset is stored in iCloud and not available locally.\n * This does not trigger a download of the asset.\n * @returns A promise resolving to `true` if the asset is stored in iCloud and not available locally.\n * @throws An exception if the asset could not be found.\n * @platform ios\n */\n getIsInCloud(): Promise;\n\n /**\n * Gets the EXIF display orientation of the asset.\n * Only applicable for assets with media type [MediaType.image](#mediatype).\n * @returns A promise resolving to a value between 1 and 8 as defined by the [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html), or `null` if unavailable.\n * @throws An exception if the asset could not be found.\n * @platform ios\n */\n getOrientation(): Promise;\n\n /**\n * Gets the last modification time of the asset.\n * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable.\n * @throws An exception if the asset could not be found.\n */\n getModificationTime(): Promise;\n\n /**\n * Gets the shape (width and height) of the asset.\n * @returns A promise resolving to the [Shape](#shape) object, or `null` if any dimension is unavailable.\n * @throws An exception if the asset could not be found.\n */\n getShape(): Promise;\n\n /**\n * Gets the URI pointing to the asset’s location in the system.\n * Example, for Android: `file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg`.\n * @returns A promise resolving to the string URI.\n * @throws An exception if the asset could not be found.\n */\n getUri(): Promise;\n\n /**\n * Gets the width of the asset in pixels.\n * Only applicable for image and video assets.\n * @returns A promise resolving to the width in pixels.\n * @throws An exception if the asset could not be found.\n */\n getWidth(): Promise;\n\n /**\n * Gets detailed information about the asset.\n * @returns A promise resolving to an [AssetInfo](#assetinfo)\n * @throws An exception if the asset could not be found.\n *\n * > **Note:** On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, which some third-party gallery apps may not use for their own favorites.\n */\n getInfo(): Promise;\n\n /**\n * Gets the albums containing this asset.\n * On Android, an asset is typically associated with a single album.\n * On iOS, an asset may belong to multiple albums.\n * @returns A promise resolving to an array of [Album](#album) objects.\n * @throws An exception if the asset could not be found.\n *\n * @example\n * ```ts\n * const albums = await asset.getAlbums();\n * console.log(albums.length);\n * ```\n */\n getAlbums(): Promise;\n\n /**\n * Gets the location of the asset.\n * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata.\n * @returns A promise resolving to the [Location](#location) object or `null` if the location data is unavailable.\n * @throws An exception if the asset could not be found, or if the permission is not granted on Android.\n */\n getLocation(): Promise;\n\n /**\n * Gets the exif data of the [MediaType.image](#mediatype) asset.\n * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata.\n * @returns A promise resolving to the exif data object or an empty object if the exif data is unavailable.\n * @throws An exception if the asset could not be found.\n */\n getExif(): Promise<{ [key: string]: any }>;\n\n /**\n * Deletes the asset from the device’s media store.\n * @returns A promise that resolves once the deletion has completed.\n *\n * @example\n * ```ts\n * await asset.delete();\n * ```\n */\n delete(): Promise;\n\n /**\n * Gets whether the asset is marked as a favorite.\n * On iOS, this checks if the asset is part of the system \"Favorites\" smart album.\n * On Android, this reads the `IS_FAVORITE` column from MediaStore (requires Android 10+; always returns `false` on older versions).\n * @returns A promise resolving to `true` if the asset is a favorite, or `false` otherwise.\n *\n * @example\n * ```ts\n * const isFavorite = await asset.getFavorite();\n * console.log(isFavorite); // true or false\n * ```\n */\n getFavorite(): Promise;\n\n /**\n * Marks or unmarks the asset as a favorite.\n * On iOS, this adds or removes the asset from the system \"Favorites\" smart album.\n * On Android, this updates the `IS_FAVORITE` column in MediaStore (requires Android 10+; no-op on older versions).\n * @param isFavorite Whether the asset should be marked as favorite.\n * @returns A promise that resolves once the operation has completed.\n *\n * > **Note:** On Android, some third-party gallery apps maintain their own favorites list and may not reflect changes made through this method.\n *\n * @example\n * ```ts\n * await asset.setFavorite(true);\n * ```\n */\n setFavorite(isFavorite: boolean): Promise;\n\n /*\n * A static function. Creates a new asset from a given file path.\n * Optionally associates the asset with an album. On Android, if not specified, the asset will be placed in the default \"Pictures\" directory.\n *\n * @param filePath - Local filesystem path (for example, `file:///...`) of the file to import.\n * @param album - Optional [Album](#album) instance to place the asset in.\n * @returns A promise resolving to the created [Asset](#asset).\n * @throws An exception if the asset could not be created, for example, if the file does not exist or permission is denied.\n *\n * @example\n * ```ts\n * const asset = await Asset.create(\"file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg\");\n * console.log(await asset.getFilename()); // \"IMG_20230915_123456.jpg\"\n * ```\n */\n static create(filePath: string, album?: Album): Promise;\n\n /**\n * A static function. Deletes multiple assets from the device's media store.\n * @param assets - An array of [Asset](#asset) instances to delete.\n * @returns A promise that resolves once the deletion has completed.\n */\n static delete(assets: Asset[]): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetField.d.ts.map b/packages/expo-media-library/build/types/AssetField.d.ts.map deleted file mode 100644 index 99f9f50009aa41..00000000000000 --- a/packages/expo-media-library/build/types/AssetField.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetField.d.ts","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,oBAAY,UAAU;IACpB,aAAa,iBAAiB;IAC9B,iBAAiB,qBAAqB;IACtC,UAAU,cAAc;IACxB,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,WAAW,eAAe;CAC3B;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;IACnC,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAC3B,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC9B,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CACnC,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetField.js.map b/packages/expo-media-library/build/types/AssetField.js.map deleted file mode 100644 index 31f2aa3275fb09..00000000000000 --- a/packages/expo-media-library/build/types/AssetField.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetField.js","sourceRoot":"","sources":["../../src/types/AssetField.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IACpB,4CAA8B,CAAA;IAC9B,oDAAsC,CAAA;IACtC,sCAAwB,CAAA;IACxB,6BAAe,CAAA;IACf,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;IACrB,wCAA0B,CAAA;AAC5B,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB","sourcesContent":["import type { MediaType } from './MediaType';\n\nexport enum AssetField {\n CREATION_TIME = 'creationTime',\n MODIFICATION_TIME = 'modificationTime',\n MEDIA_TYPE = 'mediaType',\n WIDTH = 'width',\n HEIGHT = 'height',\n DURATION = 'duration',\n IS_FAVORITE = 'isFavorite',\n}\n\nexport type AssetFieldValueMap = {\n [AssetField.CREATION_TIME]: number;\n [AssetField.MODIFICATION_TIME]: number;\n [AssetField.MEDIA_TYPE]: MediaType;\n [AssetField.WIDTH]: number;\n [AssetField.HEIGHT]: number;\n [AssetField.DURATION]: number;\n [AssetField.IS_FAVORITE]: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetInfo.d.ts b/packages/expo-media-library/build/types/AssetInfo.d.ts deleted file mode 100644 index a94b72959877e6..00000000000000 --- a/packages/expo-media-library/build/types/AssetInfo.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { MediaType } from './MediaType'; -export type AssetInfo = { - id: string; - filename: string; - uri: string; - mediaType: MediaType; - width: number; - height: number; - duration: number | null; - creationTime: number | null; - modificationTime: number | null; - isFavorite: boolean; -}; -//# sourceMappingURL=AssetInfo.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetInfo.d.ts.map b/packages/expo-media-library/build/types/AssetInfo.d.ts.map deleted file mode 100644 index 639c6fbfbb2077..00000000000000 --- a/packages/expo-media-library/build/types/AssetInfo.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetInfo.d.ts","sourceRoot":"","sources":["../../src/types/AssetInfo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetInfo.js b/packages/expo-media-library/build/types/AssetInfo.js deleted file mode 100644 index 6e73885a1532a7..00000000000000 --- a/packages/expo-media-library/build/types/AssetInfo.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=AssetInfo.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetInfo.js.map b/packages/expo-media-library/build/types/AssetInfo.js.map deleted file mode 100644 index 294d1cfbff9d79..00000000000000 --- a/packages/expo-media-library/build/types/AssetInfo.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetInfo.js","sourceRoot":"","sources":["../../src/types/AssetInfo.ts"],"names":[],"mappings":"","sourcesContent":["import type { MediaType } from './MediaType';\n\nexport type AssetInfo = {\n id: string;\n filename: string;\n uri: string;\n mediaType: MediaType;\n width: number;\n height: number;\n duration: number | null;\n creationTime: number | null;\n modificationTime: number | null;\n isFavorite: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetMetadata.d.ts b/packages/expo-media-library/build/types/AssetMetadata.d.ts deleted file mode 100644 index cf26c43ef32cb3..00000000000000 --- a/packages/expo-media-library/build/types/AssetMetadata.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { MediaType } from './MediaType'; -/** - * Lightweight metadata for a single asset, returned by [Query.exeForMetadata](#exeformetadata). - * - * Contains fields that can be read cheaply from the media store, without resolving file paths or - * decoding files. Use [Asset](#asset) getters when you need heavier fields such as URI or EXIF data. - * - * > On Android, `width` and `height` may be `null` when the media store does not record them. - */ -export type AssetMetadata = { - id: string; - filename: string | null; - mediaType: MediaType; - width: number | null; - height: number | null; - duration: number | null; - creationTime: number | null; - modificationTime: number | null; - isFavorite: boolean; -}; -//# sourceMappingURL=AssetMetadata.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetMetadata.d.ts.map b/packages/expo-media-library/build/types/AssetMetadata.d.ts.map deleted file mode 100644 index d32e8869e42592..00000000000000 --- a/packages/expo-media-library/build/types/AssetMetadata.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetMetadata.d.ts","sourceRoot":"","sources":["../../src/types/AssetMetadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,UAAU,EAAE,OAAO,CAAC;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetMetadata.js b/packages/expo-media-library/build/types/AssetMetadata.js deleted file mode 100644 index 54f2e008485dfe..00000000000000 --- a/packages/expo-media-library/build/types/AssetMetadata.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=AssetMetadata.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/AssetMetadata.js.map b/packages/expo-media-library/build/types/AssetMetadata.js.map deleted file mode 100644 index 83261a415fc5c6..00000000000000 --- a/packages/expo-media-library/build/types/AssetMetadata.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"AssetMetadata.js","sourceRoot":"","sources":["../../src/types/AssetMetadata.ts"],"names":[],"mappings":"","sourcesContent":["import type { MediaType } from './MediaType';\n\n/**\n * Lightweight metadata for a single asset, returned by [Query.exeForMetadata](#exeformetadata).\n *\n * Contains fields that can be read cheaply from the media store, without resolving file paths or\n * decoding files. Use [Asset](#asset) getters when you need heavier fields such as URI or EXIF data.\n *\n * > On Android, `width` and `height` may be `null` when the media store does not record them.\n */\nexport type AssetMetadata = {\n id: string;\n filename: string | null;\n mediaType: MediaType;\n width: number | null;\n height: number | null;\n duration: number | null;\n creationTime: number | null;\n modificationTime: number | null;\n isFavorite: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/GranularPermission.d.ts b/packages/expo-media-library/build/types/GranularPermission.d.ts deleted file mode 100644 index 00698f77a2c81b..00000000000000 --- a/packages/expo-media-library/build/types/GranularPermission.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type GranularPermission = 'audio' | 'photo' | 'video'; -//# sourceMappingURL=GranularPermission.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/GranularPermission.d.ts.map b/packages/expo-media-library/build/types/GranularPermission.d.ts.map deleted file mode 100644 index ed38564c5133a2..00000000000000 --- a/packages/expo-media-library/build/types/GranularPermission.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"GranularPermission.d.ts","sourceRoot":"","sources":["../../src/types/GranularPermission.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/GranularPermission.js b/packages/expo-media-library/build/types/GranularPermission.js deleted file mode 100644 index cf0a0ef0125c9b..00000000000000 --- a/packages/expo-media-library/build/types/GranularPermission.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=GranularPermission.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/GranularPermission.js.map b/packages/expo-media-library/build/types/GranularPermission.js.map deleted file mode 100644 index 5cbdad5955b0ec..00000000000000 --- a/packages/expo-media-library/build/types/GranularPermission.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"GranularPermission.js","sourceRoot":"","sources":["../../src/types/GranularPermission.ts"],"names":[],"mappings":"","sourcesContent":["export type GranularPermission = 'audio' | 'photo' | 'video';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Location.d.ts b/packages/expo-media-library/build/types/Location.d.ts deleted file mode 100644 index 19c737898fd0a5..00000000000000 --- a/packages/expo-media-library/build/types/Location.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type Location = { - latitude: number; - longitude: number; -}; -//# sourceMappingURL=Location.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Location.d.ts.map b/packages/expo-media-library/build/types/Location.d.ts.map deleted file mode 100644 index a824280a1b467c..00000000000000 --- a/packages/expo-media-library/build/types/Location.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Location.d.ts","sourceRoot":"","sources":["../../src/types/Location.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Location.js b/packages/expo-media-library/build/types/Location.js deleted file mode 100644 index eabc5a4932f379..00000000000000 --- a/packages/expo-media-library/build/types/Location.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=Location.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Location.js.map b/packages/expo-media-library/build/types/Location.js.map deleted file mode 100644 index dcbe60afcdb1fa..00000000000000 --- a/packages/expo-media-library/build/types/Location.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Location.js","sourceRoot":"","sources":["../../src/types/Location.ts"],"names":[],"mappings":"","sourcesContent":["export type Location = {\n latitude: number;\n longitude: number;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts.map b/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts.map deleted file mode 100644 index e4a2d31dac03f4..00000000000000 --- a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaLibraryAssetsChangeEvent.d.ts","sourceRoot":"","sources":["../../src/types/MediaLibraryAssetsChangeEvent.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,6BAA6B,GAAG;IAC1C;;;;;;OAMG;IACH,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js b/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js deleted file mode 100644 index 0439aac9c502e7..00000000000000 --- a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=MediaLibraryAssetsChangeEvent.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js.map b/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js.map deleted file mode 100644 index 241daac9693df9..00000000000000 --- a/packages/expo-media-library/build/types/MediaLibraryAssetsChangeEvent.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaLibraryAssetsChangeEvent.js","sourceRoot":"","sources":["../../src/types/MediaLibraryAssetsChangeEvent.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * An event emitted when assets in the media library change.\n */\nexport type MediaLibraryAssetsChangeEvent = {\n /**\n * Whether the media library's changes can be described as incremental changes.\n * `true` indicates the changes are described by the `insertedAssets`, `deletedAssets` and\n * `updatedAssets` values. `false` indicates that the scope of changes is too large and you\n * should perform a full assets reload.\n * On Android this is always `false` because the platform does not provide incremental change details.\n */\n hasIncrementalChanges: boolean;\n /**\n * Array of asset IDs (`ph://` URIs) that have been inserted to the library.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n insertedAssets?: string[];\n /**\n * Array of asset IDs (`ph://` URIs) that have been deleted from the library.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n deletedAssets?: string[];\n /**\n * Array of asset IDs (`ph://` URIs) that have been updated.\n * Only populated when `hasIncrementalChanges` is `true`.\n * @platform ios\n */\n updatedAssets?: string[];\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaSubtype.d.ts b/packages/expo-media-library/build/types/MediaSubtype.d.ts deleted file mode 100644 index cacb9f05eff746..00000000000000 --- a/packages/expo-media-library/build/types/MediaSubtype.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype). - * @platform ios - */ -export declare enum MediaSubtype { - DEPTH_EFFECT = "depthEffect", - HDR = "hdr", - HIGH_FRAME_RATE = "highFrameRate", - LIVE_PHOTO = "livePhoto", - PANORAMA = "panorama", - SCREENSHOT = "screenshot", - STREAM = "stream", - TIME_LAPSE = "timelapse", - SPATIAL_MEDIA = "spatialMedia", - VIDEO_CINEMATIC = "videoCinematic" -} -//# sourceMappingURL=MediaSubtype.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaSubtype.d.ts.map b/packages/expo-media-library/build/types/MediaSubtype.d.ts.map deleted file mode 100644 index 46bf5708fdbda9..00000000000000 --- a/packages/expo-media-library/build/types/MediaSubtype.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaSubtype.d.ts","sourceRoot":"","sources":["../../src/types/MediaSubtype.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,oBAAY,YAAY;IACtB,YAAY,gBAAgB;IAC5B,GAAG,QAAQ;IACX,eAAe,kBAAkB;IACjC,UAAU,cAAc;IACxB,QAAQ,aAAa;IACrB,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,UAAU,cAAc;IACxB,aAAa,iBAAiB;IAC9B,eAAe,mBAAmB;CACnC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaSubtype.js.map b/packages/expo-media-library/build/types/MediaSubtype.js.map deleted file mode 100644 index 9f4a1fa3943306..00000000000000 --- a/packages/expo-media-library/build/types/MediaSubtype.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaSubtype.js","sourceRoot":"","sources":["../../src/types/MediaSubtype.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,YAWX;AAXD,WAAY,YAAY;IACtB,4CAA4B,CAAA;IAC5B,2BAAW,CAAA;IACX,iDAAiC,CAAA;IACjC,wCAAwB,CAAA;IACxB,qCAAqB,CAAA;IACrB,yCAAyB,CAAA;IACzB,iCAAiB,CAAA;IACjB,wCAAwB,CAAA;IACxB,8CAA8B,CAAA;IAC9B,kDAAkC,CAAA;AACpC,CAAC,EAXW,YAAY,KAAZ,YAAY,QAWvB","sourcesContent":["/**\n * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype).\n * @platform ios\n */\nexport enum MediaSubtype {\n DEPTH_EFFECT = 'depthEffect',\n HDR = 'hdr',\n HIGH_FRAME_RATE = 'highFrameRate',\n LIVE_PHOTO = 'livePhoto',\n PANORAMA = 'panorama',\n SCREENSHOT = 'screenshot',\n STREAM = 'stream',\n TIME_LAPSE = 'timelapse',\n SPATIAL_MEDIA = 'spatialMedia',\n VIDEO_CINEMATIC = 'videoCinematic',\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaType.d.ts b/packages/expo-media-library/build/types/MediaType.d.ts deleted file mode 100644 index 2cc832bcc02ecb..00000000000000 --- a/packages/expo-media-library/build/types/MediaType.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export declare enum MediaType { - UNKNOWN = "unknown", - IMAGE = "image", - AUDIO = "audio", - VIDEO = "video" -} -//# sourceMappingURL=MediaType.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaType.d.ts.map b/packages/expo-media-library/build/types/MediaType.d.ts.map deleted file mode 100644 index b59abb006f6d4b..00000000000000 --- a/packages/expo-media-library/build/types/MediaType.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaType.d.ts","sourceRoot":"","sources":["../../src/types/MediaType.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,KAAK,UAAU;CAChB"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaType.js b/packages/expo-media-library/build/types/MediaType.js deleted file mode 100644 index 83c45811f158e8..00000000000000 --- a/packages/expo-media-library/build/types/MediaType.js +++ /dev/null @@ -1,8 +0,0 @@ -export var MediaType; -(function (MediaType) { - MediaType["UNKNOWN"] = "unknown"; - MediaType["IMAGE"] = "image"; - MediaType["AUDIO"] = "audio"; - MediaType["VIDEO"] = "video"; -})(MediaType || (MediaType = {})); -//# sourceMappingURL=MediaType.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaType.js.map b/packages/expo-media-library/build/types/MediaType.js.map deleted file mode 100644 index 5565f9936e831b..00000000000000 --- a/packages/expo-media-library/build/types/MediaType.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaType.js","sourceRoot":"","sources":["../../src/types/MediaType.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,gCAAmB,CAAA;IACnB,4BAAe,CAAA;IACf,4BAAe,CAAA;IACf,4BAAe,CAAA;AACjB,CAAC,EALW,SAAS,KAAT,SAAS,QAKpB","sourcesContent":["export enum MediaType {\n UNKNOWN = 'unknown',\n IMAGE = 'image',\n AUDIO = 'audio',\n VIDEO = 'video',\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaTypeFilter.d.ts b/packages/expo-media-library/build/types/MediaTypeFilter.d.ts deleted file mode 100644 index a247fed7a40caf..00000000000000 --- a/packages/expo-media-library/build/types/MediaTypeFilter.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type MediaTypeFilter = 'photo' | 'video'; -//# sourceMappingURL=MediaTypeFilter.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaTypeFilter.d.ts.map b/packages/expo-media-library/build/types/MediaTypeFilter.d.ts.map deleted file mode 100644 index fea53e37806e11..00000000000000 --- a/packages/expo-media-library/build/types/MediaTypeFilter.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaTypeFilter.d.ts","sourceRoot":"","sources":["../../src/types/MediaTypeFilter.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaTypeFilter.js b/packages/expo-media-library/build/types/MediaTypeFilter.js deleted file mode 100644 index 9e884d97e586bc..00000000000000 --- a/packages/expo-media-library/build/types/MediaTypeFilter.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=MediaTypeFilter.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/MediaTypeFilter.js.map b/packages/expo-media-library/build/types/MediaTypeFilter.js.map deleted file mode 100644 index 9a3caaaaad1043..00000000000000 --- a/packages/expo-media-library/build/types/MediaTypeFilter.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"MediaTypeFilter.js","sourceRoot":"","sources":["../../src/types/MediaTypeFilter.ts"],"names":[],"mappings":"","sourcesContent":["export type MediaTypeFilter = 'photo' | 'video';\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Query.d.ts.map b/packages/expo-media-library/build/types/Query.d.ts.map deleted file mode 100644 index f66bbf7b74ea16..00000000000000 --- a/packages/expo-media-library/build/types/Query.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Query.d.ts","sourceRoot":"","sources":["../../src/types/Query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,CAAC,OAAO,OAAO,KAAK;;IAKxB;;;;;OAKG;IACH,EAAE,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,GAAG,KAAK;IACvE;;;;;OAKG;IACH,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK;IAC7E;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAC3C;;;;OAIG;IACH,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAC5C;;;;;OAKG;IACH,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAC3C;;;;;OAKG;IACH,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK;IAC5C;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK;IAC3B;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;IAC7B;;;OAGG;IACH,OAAO,CAAC,eAAe,EAAE,cAAc,GAAG,UAAU,GAAG,KAAK;IAC5D;;;;OAIG;IACH,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK;IAC1B;;;;;;;;;;;;;OAaG;IACH,GAAG,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB;;;;;;;;;;;;;;;;;OAiBG;IACH,cAAc,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;CAC3C"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Query.js b/packages/expo-media-library/build/types/Query.js deleted file mode 100644 index 795322ffe65437..00000000000000 --- a/packages/expo-media-library/build/types/Query.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=Query.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Query.js.map b/packages/expo-media-library/build/types/Query.js.map deleted file mode 100644 index 578e123543ee94..00000000000000 --- a/packages/expo-media-library/build/types/Query.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Query.js","sourceRoot":"","sources":["../../src/types/Query.ts"],"names":[],"mappings":"","sourcesContent":["import type { Album } from './Album';\nimport type { Asset } from './Asset';\nimport type { AssetField, AssetFieldValueMap } from './AssetField';\nimport type { AssetMetadata } from './AssetMetadata';\nimport type { SortDescriptor } from './SortDescriptor';\n\n/**\n * Represents a query to fetch data from the media library.\n *\n * A `query` implements a builder pattern, allowing you to chain multiple filtering and sorting methods\n * to construct complex queries.\n */\nexport declare class Query {\n /*\n * Initializes a new, empty query.\n */\n constructor();\n /**\n * Filters assets where the specified field is equal to the given value.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - The value that the field should equal. Each field has a specific unique type.\n * @returns The updated query object for chaining.\n */\n eq(field: T, value: AssetFieldValueMap[T]): Query;\n /**\n * Filters assets where the specified field's value is in the given array of values.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - An array of values that the field should match. Each field has a specific unique type.\n * @returns The updated query object for chaining.\n */\n within(field: T, value: AssetFieldValueMap[T][]): Query;\n /**\n * Filters assets where the specified field is greater than the given value.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - The value that the field should be greater than.\n * @returns The updated query object for chaining.\n */\n gt(field: AssetField, value: number): Query;\n /**\n * Filters assets where the specified field is greater than or equal to the given value.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - The value that the field should be greater than or equal to.\n */\n gte(field: AssetField, value: number): Query;\n /**\n * Filters assets where the specified field is less than the given value.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - The value that the field should be less than.\n * @returns The updated query object for chaining.\n */\n lt(field: AssetField, value: number): Query;\n /**\n * Filters assets where the specified field is less than or equal to the given value.\n * @param field - an [AssetField](#assetfield) to filter by.\n * @param value - The value that the field should be less than or equal to.\n * @returns The updated query object for chaining.\n */\n lte(field: AssetField, value: number): Query;\n /**\n * Limits the number of results returned by the query.\n * @param limit - The maximum number of results to return.\n * @returns The updated query object for chaining.\n */\n limit(limit: number): Query;\n /**\n * Skips the specified number of results.\n * @param offset - The number of results to skip.\n * @returns The updated query object for chaining.\n */\n offset(offset: number): Query;\n /**\n * Orders the results by the specified sort descriptor or asset field.\n * @param sortDescriptors - An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default.\n */\n orderBy(sortDescriptors: SortDescriptor | AssetField): Query;\n /**\n * Filters assets to only those contained in the specified album.\n * @param album - The album to filter assets by.\n * @returns The updated query object for chaining.\n */\n album(album: Album): Query;\n /**\n * Executes the query and retrieves the matching assets.\n * @returns A promise that resolves to an array of [Asset](#asset) objects that match the query criteria.\n *\n * @example\n * ```ts\n * const assets = await new Query()\n * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n * .lte(AssetField.HEIGHT, 1080)\n * .orderBy(AssetField.CREATION_TIME)\n * .limit(20)\n * .exe();\n * ```\n */\n exe(): Promise;\n /**\n * Executes the query and retrieves lightweight metadata for the matching assets.\n *\n * Returns fields that can be read cheaply from the media store, without resolving file paths or\n * decoding files.\n *\n * @returns A promise that resolves to an array of [AssetMetadata](#assetmetadata) objects that match the query criteria.\n *\n * @example\n * ```ts\n * const assets = await new Query()\n * .eq(AssetField.MEDIA_TYPE, MediaType.IMAGE)\n * .lte(AssetField.HEIGHT, 1080)\n * .orderBy(AssetField.CREATION_TIME)\n * .limit(20)\n * .exeForMetadata();\n * ```\n */\n exeForMetadata(): Promise;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Shape.d.ts b/packages/expo-media-library/build/types/Shape.d.ts deleted file mode 100644 index 09486b31d6d382..00000000000000 --- a/packages/expo-media-library/build/types/Shape.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -export type Shape = { - width: number; - height: number; -}; -//# sourceMappingURL=Shape.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Shape.d.ts.map b/packages/expo-media-library/build/types/Shape.d.ts.map deleted file mode 100644 index c77ed69797022c..00000000000000 --- a/packages/expo-media-library/build/types/Shape.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Shape.d.ts","sourceRoot":"","sources":["../../src/types/Shape.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Shape.js b/packages/expo-media-library/build/types/Shape.js deleted file mode 100644 index be2ea883114b90..00000000000000 --- a/packages/expo-media-library/build/types/Shape.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=Shape.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/Shape.js.map b/packages/expo-media-library/build/types/Shape.js.map deleted file mode 100644 index ec834e16d3c52a..00000000000000 --- a/packages/expo-media-library/build/types/Shape.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"Shape.js","sourceRoot":"","sources":["../../src/types/Shape.ts"],"names":[],"mappings":"","sourcesContent":["export type Shape = {\n width: number;\n height: number;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/SortDescriptor.d.ts b/packages/expo-media-library/build/types/SortDescriptor.d.ts deleted file mode 100644 index c6cb35809647ed..00000000000000 --- a/packages/expo-media-library/build/types/SortDescriptor.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { AssetField } from './AssetField'; -export type SortDescriptor = { - key: AssetField; - ascending?: boolean; -}; -//# sourceMappingURL=SortDescriptor.d.ts.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/SortDescriptor.d.ts.map b/packages/expo-media-library/build/types/SortDescriptor.d.ts.map deleted file mode 100644 index 1e7a266ea8f74e..00000000000000 --- a/packages/expo-media-library/build/types/SortDescriptor.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"SortDescriptor.d.ts","sourceRoot":"","sources":["../../src/types/SortDescriptor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,GAAG,EAAE,UAAU,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/expo-media-library/build/types/SortDescriptor.js b/packages/expo-media-library/build/types/SortDescriptor.js deleted file mode 100644 index b6188b8d6ef7db..00000000000000 --- a/packages/expo-media-library/build/types/SortDescriptor.js +++ /dev/null @@ -1,2 +0,0 @@ -export {}; -//# sourceMappingURL=SortDescriptor.js.map \ No newline at end of file diff --git a/packages/expo-media-library/build/types/SortDescriptor.js.map b/packages/expo-media-library/build/types/SortDescriptor.js.map deleted file mode 100644 index edb4b194d61e2a..00000000000000 --- a/packages/expo-media-library/build/types/SortDescriptor.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"SortDescriptor.js","sourceRoot":"","sources":["../../src/types/SortDescriptor.ts"],"names":[],"mappings":"","sourcesContent":["import type { AssetField } from './AssetField';\n\nexport type SortDescriptor = {\n key: AssetField;\n ascending?: boolean;\n};\n"]} \ No newline at end of file diff --git a/packages/expo-media-library/src/ExpoMediaLibraryNext.ts b/packages/expo-media-library/src/ExpoMediaLibraryNext.ts deleted file mode 100644 index 4833c0454f77dd..00000000000000 --- a/packages/expo-media-library/src/ExpoMediaLibraryNext.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { PermissionResponse } from 'expo'; -import { NativeModule, requireNativeModule } from 'expo-modules-core'; - -import type { GranularPermission, MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types'; -import { Album } from './types/Album'; -import { Asset } from './types/Asset'; -import type { MediaTypeFilter } from './types/MediaTypeFilter'; -import { Query } from './types/Query'; - -declare class ExpoMediaLibraryNextModule extends NativeModule<{ - mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void; -}> { - Asset: typeof Asset; - Album: typeof Album; - Query: typeof Query; - - getPermissionsAsync( - writeOnly?: boolean, - granularPermissions?: GranularPermission[] - ): Promise; - requestPermissionsAsync( - writeOnly?: boolean, - granularPermissions?: GranularPermission[] - ): Promise; - presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; -} - -export default requireNativeModule('ExpoMediaLibraryNext'); diff --git a/packages/expo-media-library/src/MediaLibrary.ts b/packages/expo-media-library/src/MediaLibrary.ts index ea465c2a34a4ee..d19e42e2fcb274 100644 --- a/packages/expo-media-library/src/MediaLibrary.ts +++ b/packages/expo-media-library/src/MediaLibrary.ts @@ -1 +1,6 @@ +/** + * @hidden + * Temporary compatibility barrel for older internal imports. + * Prefer importing public APIs from the package root. + */ export * from './index'; diff --git a/packages/expo-media-library/src/MediaLibraryNext.types.ts b/packages/expo-media-library/src/MediaLibraryNext.types.ts deleted file mode 100644 index 124320b687e6a0..00000000000000 --- a/packages/expo-media-library/src/MediaLibraryNext.types.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from './types/SortDescriptor'; -export * from './types/AssetField'; -export * from './types/MediaSubtype'; -export * from './types/MediaType'; -export * from './types/MediaTypeFilter'; -export * from './types/GranularPermission'; -export * from './types/AssetInfo'; -export * from './types/AssetMetadata'; -export * from './types/Location'; -export * from './types/MediaLibraryAssetsChangeEvent'; -export * from './types/Shape'; diff --git a/packages/expo-media-library/src/__tests__/MediaLibrary-test.native.ts b/packages/expo-media-library/src/__tests__/MediaLibrary-test.native.ts index 42ca9ab24b8119..9ed2d40650dc38 100644 --- a/packages/expo-media-library/src/__tests__/MediaLibrary-test.native.ts +++ b/packages/expo-media-library/src/__tests__/MediaLibrary-test.native.ts @@ -1,6 +1,6 @@ import * as MediaLibrary from '../legacy'; -jest.mock('../ExpoMediaLibraryNext', () => ({ +jest.mock('../next/native', () => ({ __esModule: true, default: { Query: class {}, diff --git a/packages/expo-media-library/src/__tests__/MediaLibrary-test.web.ts b/packages/expo-media-library/src/__tests__/MediaLibrary-test.web.ts index ce41067cf65911..ba2d97d0ae13f3 100644 --- a/packages/expo-media-library/src/__tests__/MediaLibrary-test.web.ts +++ b/packages/expo-media-library/src/__tests__/MediaLibrary-test.web.ts @@ -1,7 +1,23 @@ -import * as MediaLibrary from '../legacy'; +import * as MediaLibrary from '..'; +import * as LegacyMediaLibrary from '../legacy'; +import * as NextMediaLibrary from '../next'; describe('isAvailableAsync', () => { it('should resolve to false on web platform', async () => { - await expect(MediaLibrary.isAvailableAsync()).resolves.toBeFalsy(); + await expect(LegacyMediaLibrary.isAvailableAsync()).resolves.toBeFalsy(); + }); +}); + +describe('next API', () => { + it('should not throw when permissions are requested on web platform from the root import', async () => { + await expect(MediaLibrary.getPermissionsAsync()).resolves.toMatchObject({ + granted: false, + }); + }); + + it('should not throw when permissions are requested on web platform from the next import', async () => { + await expect(NextMediaLibrary.getPermissionsAsync()).resolves.toMatchObject({ + granted: false, + }); }); }); diff --git a/packages/expo-media-library/src/index.ts b/packages/expo-media-library/src/index.ts index 2d926331f7a44c..ad085e91ad7b3f 100644 --- a/packages/expo-media-library/src/index.ts +++ b/packages/expo-media-library/src/index.ts @@ -1,159 +1,2 @@ -import { createPermissionHook, type PermissionResponse } from 'expo'; -import { UnavailabilityError, type EventSubscription } from 'expo-modules-core'; -import { Platform } from 'react-native'; - -import ExpoMediaLibraryNext from './ExpoMediaLibraryNext'; -import type { MediaLibraryAssetsChangeEvent } from './MediaLibraryNext.types'; -import type { GranularPermission } from './types/GranularPermission'; -import { MediaSubtype } from './types/MediaSubtype'; -import type { MediaTypeFilter } from './types/MediaTypeFilter'; - -export * from './MediaLibraryNext.types'; - -export class Query extends ExpoMediaLibraryNext.Query {} - -export class Asset extends ExpoMediaLibraryNext.Asset { - // @hidden - getMediaSubtypes(): Promise { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS'); - } - return super.getMediaSubtypes(); - } - - // @hidden - getLivePhotoVideoUri(): Promise { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError( - 'MediaLibrary', - 'getLivePhotoVideoUri is only available on iOS' - ); - } - return super.getLivePhotoVideoUri(); - } - - // @hidden - getIsInCloud(): Promise { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS'); - } - return super.getIsInCloud(); - } - - // @hidden - getOrientation(): Promise { - if (Platform.OS !== 'ios') { - throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS'); - } - return super.getOrientation(); - } -} - -export class Album extends ExpoMediaLibraryNext.Album {} - -/** - * Asks the user to grant permissions for accessing media in user's media library. - * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an - * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * - * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export async function requestPermissionsAsync( - writeOnly: boolean = false, - granularPermissions?: GranularPermission[] -): Promise { - if (!ExpoMediaLibraryNext.requestPermissionsAsync) { - throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync'); - } - if (Platform.OS === 'android') { - return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly, granularPermissions); - } - return await ExpoMediaLibraryNext.requestPermissionsAsync(writeOnly); -} - -/** - * Checks user's permissions for accessing media library. - * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. - * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has - * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. - * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. - */ -export async function getPermissionsAsync( - writeOnly: boolean = false, - granularPermissions?: GranularPermission[] -): Promise { - if (!ExpoMediaLibraryNext.getPermissionsAsync) { - throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync'); - } - if (Platform.OS === 'android') { - return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly, granularPermissions); - } - return await ExpoMediaLibraryNext.getPermissionsAsync(writeOnly); -} - -/** - * Check or request permissions to access the media library. - * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. - * - * @example - * ```ts - * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ - * writeOnly: true, - * granularPermissions: ['photo'], - * }); - * ``` - */ -export const usePermissions = createPermissionHook< - PermissionResponse, - { writeOnly?: boolean; granularPermissions?: GranularPermission[] } ->({ - getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions), - requestMethod: (options) => - requestPermissionsAsync(options?.writeOnly, options?.granularPermissions), -}); - -export { PermissionStatus, type PermissionHookOptions, type PermissionResponse } from 'expo'; -export type { EventSubscription } from 'expo-modules-core'; - -/** - * Allows the user to update the assets that your app has access to. - * The system modal is only displayed if the user originally allowed only `limited` access to their - * media library, otherwise this method is a no-op. - * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. - * - * @return A promise that either rejects if the method is unavailable, or resolves to `void`. - * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. - * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). - * If `hasIncrementalChanges` is `false`, the user changed their permissions. - * - * @platform android 14+ - * @platform ios - */ -export async function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise { - return await ExpoMediaLibraryNext.presentPermissionsPicker(mediaTypes); -} - -/** - * Subscribes for updates in user's media library. - * @param listener A callback that is fired when any assets have been inserted or deleted from the - * library. On Android it's invoked with an empty object. On iOS it's invoked with - * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. - * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when - * you would like to unsubscribe the listener. - */ -export function addListener( - listener: (event: MediaLibraryAssetsChangeEvent) => void -): EventSubscription { - return ExpoMediaLibraryNext.addListener('mediaLibraryDidChange', listener); -} - -/** - * Removes all listeners. - */ -export function removeAllListeners(): void { - ExpoMediaLibraryNext.removeAllListeners('mediaLibraryDidChange'); -} - +export * from './next'; export * from './legacyWarnings'; diff --git a/packages/expo-media-library/src/ExpoMediaLibrary.ts b/packages/expo-media-library/src/legacy/ExpoMediaLibrary.ts similarity index 100% rename from packages/expo-media-library/src/ExpoMediaLibrary.ts rename to packages/expo-media-library/src/legacy/ExpoMediaLibrary.ts diff --git a/packages/expo-media-library/src/ExpoMediaLibrary.web.ts b/packages/expo-media-library/src/legacy/ExpoMediaLibrary.web.ts similarity index 92% rename from packages/expo-media-library/src/ExpoMediaLibrary.web.ts rename to packages/expo-media-library/src/legacy/ExpoMediaLibrary.web.ts index f6bc1a8bfec2b0..69aeeb99c3e690 100644 --- a/packages/expo-media-library/src/ExpoMediaLibrary.web.ts +++ b/packages/expo-media-library/src/legacy/ExpoMediaLibrary.web.ts @@ -1,6 +1,6 @@ import { type PermissionResponse, PermissionStatus } from 'expo'; -import type { MediaTypeObject, SortByObject } from './legacy/MediaLibrary'; +import type { MediaTypeObject, SortByObject } from './MediaLibrary'; const noPermissionResponse: PermissionResponse = { status: PermissionStatus.UNDETERMINED, diff --git a/packages/expo-media-library/src/legacy/MediaLibrary.ts b/packages/expo-media-library/src/legacy/MediaLibrary.ts index 2c733bafff7a09..1db86aabed114b 100644 --- a/packages/expo-media-library/src/legacy/MediaLibrary.ts +++ b/packages/expo-media-library/src/legacy/MediaLibrary.ts @@ -2,7 +2,7 @@ import { type PermissionResponse as EXPermissionResponse, createPermissionHook } import { UnavailabilityError, type EventSubscription } from 'expo-modules-core'; import { Platform } from 'react-native'; -import MediaLibrary from '../ExpoMediaLibrary'; +import MediaLibrary from './ExpoMediaLibrary'; const isExpoGo = typeof expo !== 'undefined' && globalThis.expo?.modules?.ExpoGo; diff --git a/packages/expo-media-library/src/next/index.ts b/packages/expo-media-library/src/next/index.ts index ccf57617869e78..5bc0f058c3b089 100644 --- a/packages/expo-media-library/src/next/index.ts +++ b/packages/expo-media-library/src/next/index.ts @@ -1 +1,31 @@ -export * from '..'; +export { + Asset, + Album, + Query, + requestPermissionsAsync, + getPermissionsAsync, + usePermissions, + presentPermissionsPicker, + addListener, + removeAllListeners, +} from './js'; + +export { + AssetField, + MediaSubtype, + MediaType, + type Shape, + type Location, + type AssetFieldValueMap, + type AssetInfo, + type GranularPermission, + type MediaLibraryAssetsChangeEvent, + type MediaTypeFilter, + PermissionStatus, + type EventSubscription, + type PermissionExpiration, + type PermissionHookOptions, + type PermissionResponse, + type SortDescriptor, + type Subscription, +} from './types'; diff --git a/packages/expo-media-library/src/types/Album.ts b/packages/expo-media-library/src/next/js/Album.ts similarity index 53% rename from packages/expo-media-library/src/types/Album.ts rename to packages/expo-media-library/src/next/js/Album.ts index 40b006ca1e1079..915b90adfaf89e 100644 --- a/packages/expo-media-library/src/types/Album.ts +++ b/packages/expo-media-library/src/next/js/Album.ts @@ -1,28 +1,33 @@ -import type { Asset } from './Asset'; +import { Asset } from './Asset'; +import { NativeAsset, NativeAlbum } from '../native'; /** * Represents a media album (collection of assets) on the device. * - * An [Album](#album) groups together media assets (images, videos, or audio files). - * To create a new album, use [Album.create](#albumcreate). - * To fetch an existing album, use [Album.get](#albumget). + * An [`Album`](#album) groups together media assets (images, videos, or audio files). + * To create a new album, use `Album.create()`. + * To fetch an existing album, use `Album.get()`. */ -export declare class Album { +export class Album { /** - * Reinitialize an instance of an album with a given ID. - * @param id - The unique identifier of the album. + * Unique identifier of the album. + * Can be used to re-instantiate an [`Album`](#album) later. */ - constructor(id: string); + readonly id: string; + private readonly nativeAlbum: InstanceType; /** - * Unique identifier of the album. - * Can be used to re-instantiate an [Album](#album) later. + * Creates an Album instance from its ID. + * @param id - The unique identifier of the album. */ - id: string; + constructor(id: string) { + this.id = id; + this.nativeAlbum = new NativeAlbum(id); + } /** * Retrieves all assets contained in the album. - * @returns A promise resolving to an array of [Asset](#asset) objects. + * @returns A promise resolving to an array of [`Asset`](#asset) objects. * * @example * ```ts @@ -30,12 +35,15 @@ export declare class Album { * console.log(assets.length); * ``` */ - getAssets(): Promise; + async getAssets(): Promise { + const natives = await this.nativeAlbum.getAssets(); + return natives.map((a) => new Asset(a.id)); + } /** * Gets the display title (name) of the album. * Note that album titles are not guaranteed to be unique. - * @returns A promise resolving to the album’s title string. + * @returns A promise resolving to the album's title string. * * @example * ```ts @@ -43,7 +51,9 @@ export declare class Album { * console.log(title); // "Camera" * ``` */ - getTitle(): Promise; + getTitle(): Promise { + return this.nativeAlbum.getTitle(); + } /** * Permanently deletes the album from the device. @@ -57,11 +67,13 @@ export declare class Album { * await album.delete(); * ``` */ - delete(): Promise; + delete(): Promise { + return this.nativeAlbum.delete(); + } /** * Adds one or more assets to the album. - * @param assets - The [Asset](#asset) or list of [Asset](#asset) objects to add. + * @param assets - The [`Asset`](#asset) or list of [`Asset`](#asset) objects to add. * @returns A promise that resolves once the assets have been added. * * @example @@ -75,7 +87,12 @@ export declare class Album { * await album.add([asset1, asset2]); * ``` */ - add(assets: Asset | Asset[]): Promise; + add(assets: Asset | Asset[]): Promise { + const nativeAssets = Array.isArray(assets) + ? assets.map((a) => new NativeAsset(a.id)) + : new NativeAsset(assets.id); + return this.nativeAlbum.add(nativeAssets); + } /** * Removes assets from the album without deleting them from the library. @@ -84,7 +101,7 @@ export declare class Album { * On Android, an asset can belong to only one album. To remove it from an album, * delete it or add it to another album. * @platform ios - * @param assets - An array of [Asset](#asset) objects to remove from the album. + * @param assets - An array of [`Asset`](#asset) objects to remove from the album. * @returns A promise that resolves once the assets have been removed. * * @example @@ -93,16 +110,18 @@ export declare class Album { * await album.removeAssets(assets.slice(0, 2)); * ``` */ - removeAssets(assets: Asset[]): Promise; + removeAssets(assets: Asset[]): Promise { + return this.nativeAlbum.removeAssets(assets.map((a) => new NativeAsset(a.id))); + } /** * A static function. Creates a new album with a given name and assets. * On Android, if assets are provided and `moveAssets` is true, the assets will be moved into the new album. If false or not supported, the assets will be copied. * * @param name - Name of the new album. - * @param assetsRefs - List of [Asset](#asset) objects or file paths (file:///...) to include. + * @param assetsRefs - List of [`Asset`](#asset) objects or file paths (file:///...) to include. * @param moveAssets - On Android, whether to move assets into the album. Defaults to `true`. - * @returns A promise resolving to the created [Album](#album). + * @returns A promise resolving to the created [`Album`](#album). * * @example * ```ts @@ -110,12 +129,23 @@ export declare class Album { * console.log(await album.getTitle()); // "My Album" * ``` */ - static create(name: string, assetsRefs: string[] | Asset[], moveAssets?: boolean): Promise; + static async create( + name: string, + assetsRefs: string[] | Asset[], + moveAssets?: boolean + ): Promise { + const nativeRefs = + assetsRefs.length === 0 || typeof (assetsRefs as string[])[0] === 'string' + ? (assetsRefs as string[]) + : (assetsRefs as Asset[]).map((a) => new NativeAsset(a.id)); + const native = await NativeAlbum.create(name, nativeRefs, moveAssets); + return new Album(native.id); + } /** * A static function. Deletes multiple albums at once. * On Android, assets are always deleted along with the album regardless of `deleteAssets`. - * @param albums - An array of [Album](#album) instances to delete. + * @param albums - An array of [`Album`](#album) instances to delete. * @param deleteAssets - On iOS, whether to delete the assets in the albums as well. Defaults to `false`. * @returns A promise that resolves once the albums have been deleted. * @@ -125,12 +155,17 @@ export declare class Album { * await Album.delete([album]); * ``` */ - static delete(albums: Album[], deleteAssets?: boolean): Promise; + static async delete(albums: Album[], deleteAssets?: boolean): Promise { + return NativeAlbum.delete( + albums.map((a) => new NativeAlbum(a.id)), + deleteAssets + ); + } /** * A static function. Retrieves an album by its title. * @param title - The title of the album to retrieve. - * @return A promise resolving to the [Album](#album) if found, or `null` if not found. + * @return A promise resolving to the [`Album`](#album) if found, or `null` if not found. * * @example * ```ts @@ -140,16 +175,22 @@ export declare class Album { * } * ``` */ - static get(title: string): Promise; + static async get(title: string): Promise { + const native = await NativeAlbum.get(title); + return native ? new Album(native.id) : null; + } /** * A static function. Retrieves all albums on the device. - * @returns A promise resolving to an array of [Album](#album) objects. + * @returns A promise resolving to an array of [`Album`](#album) objects. * * @example * ```ts * const albums = await Album.getAll(); * ``` */ - static getAll(): Promise; + static async getAll(): Promise { + const natives = await NativeAlbum.getAll(); + return natives.map((a) => new Album(a.id)); + } } diff --git a/packages/expo-media-library/src/next/js/Asset.ts b/packages/expo-media-library/src/next/js/Asset.ts new file mode 100644 index 00000000000000..75a0b80385db58 --- /dev/null +++ b/packages/expo-media-library/src/next/js/Asset.ts @@ -0,0 +1,246 @@ +import { UnavailabilityError } from 'expo-modules-core'; +import { Platform } from 'react-native'; + +import { Album } from './Album'; +import { NativeAsset, NativeAlbum } from '../native'; +import type { AssetInfo, Location, MediaSubtype, MediaType, Shape } from '../types'; + +/** + * Represents a media asset in the device media library. + */ +export class Asset { + /** + * Asset identifier. + * Can be used to re-instantiate an [`Asset`](#asset) later. + */ + readonly id: string; + private readonly nativeAsset: InstanceType; + + /** + * Creates an Asset instance from its ID. + * @param id - The asset identifier. On Android, this is a `content://` URI. On iOS, this is a `PHAsset` local identifier URI. + */ + constructor(id: string) { + this.id = id; + this.nativeAsset = new NativeAsset(id); + } + + /** + * Gets the asset creation time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getCreationTime(): Promise { + return this.nativeAsset.getCreationTime(); + } + + /** + * Gets the asset duration. + * @returns A promise resolving to the duration in seconds, or `null` when the value is unavailable. + */ + getDuration(): Promise { + return this.nativeAsset.getDuration(); + } + + /** + * Gets the asset filename. + * @returns A promise resolving to the asset filename. + */ + getFilename(): Promise { + return this.nativeAsset.getFilename(); + } + + /** + * Gets the asset height. + * @returns A promise resolving to the asset height in pixels. + */ + getHeight(): Promise { + return this.nativeAsset.getHeight(); + } + + /** + * Gets the asset media type. + * @returns A promise resolving to the asset media type. + */ + getMediaType(): Promise { + return this.nativeAsset.getMediaType(); + } + + /** + * Gets the asset modification time. + * @returns A promise resolving to a timestamp in seconds, or `null` when the value is unavailable. + */ + getModificationTime(): Promise { + return this.nativeAsset.getModificationTime(); + } + + /** + * Gets the asset dimensions. + * @returns A promise resolving to the asset shape, or `null` when the value is unavailable. + */ + getShape(): Promise { + return this.nativeAsset.getShape(); + } + + /** + * Gets the asset URI. + * @returns A promise resolving to the asset URI. + */ + getUri(): Promise { + return this.nativeAsset.getUri(); + } + + /** + * Gets the asset width. + * @returns A promise resolving to the asset width in pixels. + */ + getWidth(): Promise { + return this.nativeAsset.getWidth(); + } + + /** + * Gets complete information about the asset. + * @returns A promise resolving to an [`AssetInfo`](#assetinfo) object. + * + * > On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, + * > which some third-party gallery apps may not use for their own favorites. + */ + getInfo(): Promise { + return this.nativeAsset.getInfo(); + } + + /** + * Gets the asset location. + * @returns A promise resolving to the asset location, or `null` when location is unavailable. + */ + getLocation(): Promise { + return this.nativeAsset.getLocation(); + } + + /** + * Gets the asset EXIF metadata. + * @returns A promise resolving to a map of EXIF tags. + */ + getExif(): Promise<{ [key: string]: any }> { + return this.nativeAsset.getExif(); + } + + /** + * Deletes the asset from the media library. + * @returns A promise resolving once the deletion has completed. + */ + delete(): Promise { + return this.nativeAsset.delete(); + } + + /** + * Gets albums that contain the asset. + * @returns A promise resolving to an array of [`Album`](#album) objects. + */ + async getAlbums(): Promise { + const natives = await this.nativeAsset.getAlbums(); + return natives.map((a) => new Album(a.id)); + } + + /** + * Creates an asset from a local file path. + * @param filePath - Local file URI of the asset to create. + * @param album - Optional album to add the created asset to. + * @returns A promise resolving to the created [`Asset`](#asset). + */ + static async create(filePath: string, album?: Album): Promise { + const native = await NativeAsset.create( + filePath, + album ? new NativeAlbum(album.id) : undefined + ); + return new Asset(native.id); + } + + /** + * Deletes multiple assets from the media library. + * @param assets - Assets to delete. + * @returns A promise resolving once deletion has completed. + */ + static async delete(assets: Asset[]): Promise { + return NativeAsset.delete(assets.map((a) => new NativeAsset(a.id))); + } + + /** + * Gets whether the asset is marked as a favorite. + * On iOS, this checks if the asset is part of the system "Favorites" smart album. + * On Android, this reads the `IS_FAVORITE` column from MediaStore. It requires Android 10+ + * and always returns `false` on older versions. + * @returns A promise resolving to `true` if the asset is a favorite, otherwise `false`. + */ + getFavorite(): Promise { + return this.nativeAsset.getFavorite(); + } + + /** + * Marks or unmarks the asset as a favorite. + * On iOS, this adds or removes the asset from the system "Favorites" smart album. + * On Android, this updates the `IS_FAVORITE` column in MediaStore. It requires Android 10+ + * and is a no-op on older versions. + * @param isFavorite - Whether the asset should be marked as favorite. + * @returns A promise that resolves once the favorite state has been updated. + * + * > On Android, some third-party gallery apps maintain their own favorites list and may not + * > reflect changes made through this method. + */ + setFavorite(isFavorite: boolean): Promise { + return this.nativeAsset.setFavorite(isFavorite); + } + + /** + * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc. + * @returns A promise resolving to an array of [`MediaSubtype`](#mediasubtype) values. + * @platform ios + */ + getMediaSubtypes(): Promise { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getMediaSubtypes is only available on iOS'); + } + return this.nativeAsset.getMediaSubtypes(); + } + + /** + * Gets the URI of the paired video for a Live Photo asset. + * The video is extracted to a temporary file. + * @returns A promise resolving to the paired video URI, or `null` if the asset is not a Live Photo or no paired video is available. + * @platform ios + */ + getLivePhotoVideoUri(): Promise { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError( + 'MediaLibrary', + 'getLivePhotoVideoUri is only available on iOS' + ); + } + return this.nativeAsset.getLivePhotoVideoUri(); + } + + /** + * Gets whether the asset is stored in iCloud and not available locally. + * This does not trigger a download of the asset. + * @returns A promise resolving to `true` if the asset is stored in iCloud and unavailable locally, otherwise `false`. + * @platform ios + */ + getIsInCloud(): Promise { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getIsInCloud is only available on iOS'); + } + return this.nativeAsset.getIsInCloud(); + } + + /** + * Gets the EXIF display orientation of the asset. + * Only applicable for assets with media type `MediaType.IMAGE`. + * @returns A promise resolving to the EXIF orientation value, or `null` when unavailable. + * @platform ios + */ + getOrientation(): Promise { + if (Platform.OS !== 'ios') { + throw new UnavailabilityError('MediaLibrary', 'getOrientation is only available on iOS'); + } + return this.nativeAsset.getOrientation(); + } +} diff --git a/packages/expo-media-library/src/next/js/Permissions.ts b/packages/expo-media-library/src/next/js/Permissions.ts new file mode 100644 index 00000000000000..4ec39c612fef48 --- /dev/null +++ b/packages/expo-media-library/src/next/js/Permissions.ts @@ -0,0 +1,87 @@ +import { createPermissionHook, type PermissionResponse } from 'expo'; +import { UnavailabilityError } from 'expo-modules-core'; +import { Platform } from 'react-native'; + +import { NativeMediaLibraryModule } from '../native'; +import type { GranularPermission, MediaTypeFilter } from '../types'; + +/** + * Asks the user to grant permissions for accessing media in user's media library. + * @param writeOnly - Whether to request write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has an + * effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * + * > When using granular permissions with a custom config plugin configuration, make sure that all the requested permissions are included in the plugin. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export async function requestPermissionsAsync( + writeOnly: boolean = false, + granularPermissions?: GranularPermission[] +): Promise { + if (!NativeMediaLibraryModule.requestPermissionsAsync) { + throw new UnavailabilityError('MediaLibrary', 'requestPermissionsAsync'); + } + if (Platform.OS === 'android') { + return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly, granularPermissions); + } + return await NativeMediaLibraryModule.requestPermissionsAsync(writeOnly); +} + +/** + * Checks user's permissions for accessing media library. + * @param writeOnly - Whether to check write-only access without read permissions. Defaults to `false`. + * @param granularPermissions - A list of [`GranularPermission`](#granularpermission) values. This parameter has + * an effect only on Android 13 and newer. By default, `expo-media-library` will ask for all possible permissions. + * @return A promise that fulfils with [`PermissionResponse`](#permissionresponse) object. + */ +export async function getPermissionsAsync( + writeOnly: boolean = false, + granularPermissions?: GranularPermission[] +): Promise { + if (!NativeMediaLibraryModule.getPermissionsAsync) { + throw new UnavailabilityError('MediaLibrary', 'getPermissionsAsync'); + } + if (Platform.OS === 'android') { + return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly, granularPermissions); + } + return await NativeMediaLibraryModule.getPermissionsAsync(writeOnly); +} + +/** + * Check or request permissions to access the media library. + * This uses both `requestPermissionsAsync` and `getPermissionsAsync` to interact with the permissions. + * + * @example + * ```ts + * const [permissionResponse, requestPermission] = MediaLibrary.usePermissions({ + * writeOnly: true, + * granularPermissions: ['photo'], + * }); + * ``` + */ +export const usePermissions = createPermissionHook< + PermissionResponse, + { writeOnly?: boolean; granularPermissions?: GranularPermission[] } +>({ + getMethod: (options) => getPermissionsAsync(options?.writeOnly, options?.granularPermissions), + requestMethod: (options) => + requestPermissionsAsync(options?.writeOnly, options?.granularPermissions), +}); + +/** + * Allows the user to update the assets that your app has access to. + * The system modal is only displayed if the user originally allowed only `limited` access to their + * media library, otherwise this method is a no-op. + * @param mediaTypes Limits the type(s) of media that the user will be granting access to. By default, a list that shows both photos and videos is presented. + * + * @return A promise that either rejects if the method is unavailable, or resolves to `void`. + * > __Note:__ This method doesn't inform you if the user changes which assets your app has access to. + * That information is only exposed by iOS, and to obtain it, you need to subscribe for updates to the user's media library using [`addListener()`](#medialibraryaddlistenerlistener). + * If `hasIncrementalChanges` is `false`, the user changed their permissions. + * + * @platform android 14+ + * @platform ios + */ +export async function presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise { + return await NativeMediaLibraryModule.presentPermissionsPicker(mediaTypes); +} diff --git a/packages/expo-media-library/src/types/Query.ts b/packages/expo-media-library/src/next/js/Query.ts similarity index 58% rename from packages/expo-media-library/src/types/Query.ts rename to packages/expo-media-library/src/next/js/Query.ts index e4dbd51ebd0c12..d33c64e5c342e9 100644 --- a/packages/expo-media-library/src/types/Query.ts +++ b/packages/expo-media-library/src/next/js/Query.ts @@ -1,8 +1,7 @@ import type { Album } from './Album'; -import type { Asset } from './Asset'; -import type { AssetField, AssetFieldValueMap } from './AssetField'; -import type { AssetMetadata } from './AssetMetadata'; -import type { SortDescriptor } from './SortDescriptor'; +import { Asset } from './Asset'; +import { NativeAlbum, NativeQuery } from '../native'; +import type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../types'; /** * Represents a query to fetch data from the media library. @@ -10,78 +9,122 @@ import type { SortDescriptor } from './SortDescriptor'; * A `query` implements a builder pattern, allowing you to chain multiple filtering and sorting methods * to construct complex queries. */ -export declare class Query { - /* - * Initializes a new, empty query. - */ - constructor(); +export class Query { + private readonly nativeQuery: InstanceType; + + constructor() { + this.nativeQuery = new NativeQuery(); + } + /** * Filters assets where the specified field is equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should equal. Each field has a specific unique type. * @returns The updated query object for chaining. */ - eq(field: T, value: AssetFieldValueMap[T]): Query; + eq(field: T, value: AssetFieldValueMap[T]): Query { + this.nativeQuery.eq(field, value); + return this; + } + /** * Filters assets where the specified field's value is in the given array of values. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - An array of values that the field should match. Each field has a specific unique type. * @returns The updated query object for chaining. */ - within(field: T, value: AssetFieldValueMap[T][]): Query; + within(field: T, value: AssetFieldValueMap[T][]): Query { + this.nativeQuery.within(field, value); + return this; + } + /** * Filters assets where the specified field is greater than the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be greater than. * @returns The updated query object for chaining. */ - gt(field: AssetField, value: number): Query; + gt(field: AssetField, value: number): Query { + this.nativeQuery.gt(field, value); + return this; + } + /** * Filters assets where the specified field is greater than or equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be greater than or equal to. + * @returns The updated query object for chaining. */ - gte(field: AssetField, value: number): Query; + gte(field: AssetField, value: number): Query { + this.nativeQuery.gte(field, value); + return this; + } + /** * Filters assets where the specified field is less than the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be less than. * @returns The updated query object for chaining. */ - lt(field: AssetField, value: number): Query; + lt(field: AssetField, value: number): Query { + this.nativeQuery.lt(field, value); + return this; + } + /** * Filters assets where the specified field is less than or equal to the given value. - * @param field - an [AssetField](#assetfield) to filter by. + * @param field - an [`AssetField`](#assetfield) to filter by. * @param value - The value that the field should be less than or equal to. * @returns The updated query object for chaining. */ - lte(field: AssetField, value: number): Query; + lte(field: AssetField, value: number): Query { + this.nativeQuery.lte(field, value); + return this; + } + /** * Limits the number of results returned by the query. * @param limit - The maximum number of results to return. * @returns The updated query object for chaining. */ - limit(limit: number): Query; + limit(limit: number): Query { + this.nativeQuery.limit(limit); + return this; + } + /** * Skips the specified number of results. * @param offset - The number of results to skip. * @returns The updated query object for chaining. */ - offset(offset: number): Query; + offset(offset: number): Query { + this.nativeQuery.offset(offset); + return this; + } + /** * Orders the results by the specified sort descriptor or asset field. * @param sortDescriptors - An instance of SortDescriptor or an AssetField. If an AssetField is provided, the sorting will be done in ascending order by default. + * @returns The updated query object for chaining. */ - orderBy(sortDescriptors: SortDescriptor | AssetField): Query; + orderBy(sortDescriptors: SortDescriptor | AssetField): Query { + this.nativeQuery.orderBy(sortDescriptors); + return this; + } + /** * Filters assets to only those contained in the specified album. * @param album - The album to filter assets by. * @returns The updated query object for chaining. */ - album(album: Album): Query; + album(album: Album): Query { + this.nativeQuery.album(new NativeAlbum(album.id)); + return this; + } + /** * Executes the query and retrieves the matching assets. - * @returns A promise that resolves to an array of [Asset](#asset) objects that match the query criteria. + * @returns A promise that resolves to an array of [`Asset`](#asset) objects that match the query criteria. * * @example * ```ts @@ -93,14 +136,18 @@ export declare class Query { * .exe(); * ``` */ - exe(): Promise; + async exe(): Promise { + const natives = await this.nativeQuery.exe(); + return natives.map((a) => new Asset(a.id)); + } + /** * Executes the query and retrieves lightweight metadata for the matching assets. * * Returns fields that can be read cheaply from the media store, without resolving file paths or * decoding files. * - * @returns A promise that resolves to an array of [AssetMetadata](#assetmetadata) objects that match the query criteria. + * @returns A promise that resolves to an array of [`AssetMetadata`](#assetmetadata) objects that match the query criteria. * * @example * ```ts @@ -112,5 +159,7 @@ export declare class Query { * .exeForMetadata(); * ``` */ - exeForMetadata(): Promise; + exeForMetadata(): Promise { + return this.nativeQuery.exeForMetadata(); + } } diff --git a/packages/expo-media-library/src/next/js/Subscriptions.ts b/packages/expo-media-library/src/next/js/Subscriptions.ts new file mode 100644 index 00000000000000..c09de2ae093203 --- /dev/null +++ b/packages/expo-media-library/src/next/js/Subscriptions.ts @@ -0,0 +1,25 @@ +import { type EventSubscription } from 'expo-modules-core'; + +import { NativeMediaLibraryModule } from '../native'; +import type { MediaLibraryAssetsChangeEvent } from '../types'; + +/** + * Subscribes for updates in user's media library. + * @param listener A callback that is fired when any assets have been inserted or deleted from the + * library. On Android it's invoked with an empty object. On iOS it's invoked with + * [`MediaLibraryAssetsChangeEvent`](#medialibraryassetschangeevent) object. + * @return An [`EventSubscription`](#eventsubscription) object that you can call `remove()` on when + * you would like to unsubscribe the listener. + */ +export function addListener( + listener: (event: MediaLibraryAssetsChangeEvent) => void +): EventSubscription { + return NativeMediaLibraryModule.addListener('mediaLibraryDidChange', listener); +} + +/** + * Removes all listeners. + */ +export function removeAllListeners(): void { + NativeMediaLibraryModule.removeAllListeners('mediaLibraryDidChange'); +} diff --git a/packages/expo-media-library/src/next/js/index.ts b/packages/expo-media-library/src/next/js/index.ts new file mode 100644 index 00000000000000..54794cc98f44fe --- /dev/null +++ b/packages/expo-media-library/src/next/js/index.ts @@ -0,0 +1,10 @@ +export { Asset } from './Asset'; +export { Album } from './Album'; +export { Query } from './Query'; +export { + requestPermissionsAsync, + getPermissionsAsync, + usePermissions, + presentPermissionsPicker, +} from './Permissions'; +export { addListener, removeAllListeners } from './Subscriptions'; diff --git a/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.ts b/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.ts new file mode 100644 index 00000000000000..a093c9361ea5b7 --- /dev/null +++ b/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.ts @@ -0,0 +1,9 @@ +import { requireNativeModule } from 'expo'; + +import type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types'; + +export const NativeMediaLibraryModule = + requireNativeModule('ExpoMediaLibraryNext'); +export const NativeAsset = NativeMediaLibraryModule.Asset; +export const NativeAlbum = NativeMediaLibraryModule.Album; +export const NativeQuery = NativeMediaLibraryModule.Query; diff --git a/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.web.ts b/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.web.ts new file mode 100644 index 00000000000000..452238d4e9d13f --- /dev/null +++ b/packages/expo-media-library/src/next/native/NativeMediaLibraryModule.web.ts @@ -0,0 +1,219 @@ +import { PermissionStatus, type PermissionResponse } from 'expo'; +import { type EventSubscription, UnavailabilityError } from 'expo-modules-core'; + +import type { + AssetField, + AssetFieldValueMap, + AssetMetadata, + GranularPermission, + MediaTypeFilter, + MediaLibraryAssetsChangeEvent, + SortDescriptor, +} from '../types'; +import type { NativeAlbumClass } from './types/NativeAlbumClass.types'; +import type { NativeAssetClass } from './types/NativeAssetClass.types'; +import type { NativeMediaLibraryModuleClass } from './types/NativeMediaLibraryModuleClass.types'; +import type { NativeQueryClass } from './types/NativeQueryClass.types'; + +const noPermissionResponse: PermissionResponse = { + status: PermissionStatus.UNDETERMINED, + canAskAgain: true, + granted: false, + expires: 'never', +}; + +function unavailable(methodName: string): never { + throw new UnavailabilityError('MediaLibrary', methodName); +} + +class NativeAssetWeb implements NativeAssetClass { + id: string; + + constructor(id: string) { + this.id = id; + } + + getCreationTime() { + return unavailable('Asset.getCreationTime'); + } + getDuration() { + return unavailable('Asset.getDuration'); + } + getFilename() { + return unavailable('Asset.getFilename'); + } + getHeight() { + return unavailable('Asset.getHeight'); + } + getMediaType() { + return unavailable('Asset.getMediaType'); + } + getMediaSubtypes() { + return unavailable('Asset.getMediaSubtypes'); + } + getLivePhotoVideoUri() { + return unavailable('Asset.getLivePhotoVideoUri'); + } + getIsInCloud() { + return unavailable('Asset.getIsInCloud'); + } + getOrientation() { + return unavailable('Asset.getOrientation'); + } + getModificationTime() { + return unavailable('Asset.getModificationTime'); + } + getShape() { + return unavailable('Asset.getShape'); + } + getUri() { + return unavailable('Asset.getUri'); + } + getWidth() { + return unavailable('Asset.getWidth'); + } + getInfo() { + return unavailable('Asset.getInfo'); + } + getAlbums() { + return unavailable('Asset.getAlbums'); + } + getLocation() { + return unavailable('Asset.getLocation'); + } + getExif() { + return unavailable('Asset.getExif'); + } + delete() { + return unavailable('Asset.delete'); + } + getFavorite() { + return unavailable('Asset.getFavorite'); + } + setFavorite(_isFavorite: boolean) { + return unavailable('Asset.setFavorite'); + } + + static create(_filePath: string, _album?: NativeAlbumClass): Promise { + return unavailable('Asset.create'); + } + + static delete(_assets: NativeAssetClass[]): Promise { + return unavailable('Asset.delete'); + } +} + +class NativeAlbumWeb implements NativeAlbumClass { + id: string; + + constructor(id: string) { + this.id = id; + } + + getAssets() { + return unavailable('Album.getAssets'); + } + getTitle() { + return unavailable('Album.getTitle'); + } + delete() { + return unavailable('Album.delete'); + } + add(_assets: NativeAssetClass | NativeAssetClass[]) { + return unavailable('Album.add'); + } + removeAssets(_assets: NativeAssetClass[]) { + return unavailable('Album.removeAssets'); + } + + static create( + _name: string, + _assetsRefs: string[] | NativeAssetClass[], + _moveAssets?: boolean + ): Promise { + return unavailable('Album.create'); + } + + static delete(_albums: NativeAlbumClass[], _deleteAssets?: boolean): Promise { + return unavailable('Album.delete'); + } + + static get(_title: string): Promise { + return unavailable('Album.get'); + } + + static getAll(): Promise { + return unavailable('Album.getAll'); + } +} + +class NativeQueryWeb implements NativeQueryClass { + eq(_field: T, _value: AssetFieldValueMap[T]) { + return this; + } + within(_field: T, _value: AssetFieldValueMap[T][]) { + return this; + } + gt(_field: AssetField, _value: number) { + return this; + } + gte(_field: AssetField, _value: number) { + return this; + } + lt(_field: AssetField, _value: number) { + return this; + } + lte(_field: AssetField, _value: number) { + return this; + } + limit(_limit: number) { + return this; + } + offset(_offset: number) { + return this; + } + orderBy(_sortDescriptors: SortDescriptor | AssetField) { + return this; + } + album(_album: NativeAlbumClass) { + return this; + } + exe(): Promise { + return unavailable('Query.exe'); + } + exeForMetadata(): Promise { + return unavailable('Query.exeForMetadata'); + } +} + +export const NativeMediaLibraryModule = { + Asset: NativeAssetWeb, + Album: NativeAlbumWeb, + Query: NativeQueryWeb, + getPermissionsAsync( + _writeOnly?: boolean, + _granularPermissions?: GranularPermission[] + ): Promise { + return Promise.resolve(noPermissionResponse); + }, + requestPermissionsAsync( + _writeOnly?: boolean, + _granularPermissions?: GranularPermission[] + ): Promise { + return Promise.resolve(noPermissionResponse); + }, + presentPermissionsPicker(_mediaTypes?: MediaTypeFilter[]): Promise { + return unavailable('presentPermissionsPicker'); + }, + addListener( + _eventName: 'mediaLibraryDidChange', + _listener: (event: MediaLibraryAssetsChangeEvent) => void + ): EventSubscription { + return { remove() {} }; + }, + removeAllListeners(_eventName: 'mediaLibraryDidChange'): void {}, +} as unknown as NativeMediaLibraryModuleClass; + +export const NativeAsset = NativeMediaLibraryModule.Asset; +export const NativeAlbum = NativeMediaLibraryModule.Album; +export const NativeQuery = NativeMediaLibraryModule.Query; diff --git a/packages/expo-media-library/src/next/native/index.ts b/packages/expo-media-library/src/next/native/index.ts new file mode 100644 index 00000000000000..9cc713947d624d --- /dev/null +++ b/packages/expo-media-library/src/next/native/index.ts @@ -0,0 +1,6 @@ +export { + NativeMediaLibraryModule, + NativeAsset, + NativeAlbum, + NativeQuery, +} from './NativeMediaLibraryModule'; diff --git a/packages/expo-media-library/src/next/native/types/NativeAlbumClass.types.ts b/packages/expo-media-library/src/next/native/types/NativeAlbumClass.types.ts new file mode 100644 index 00000000000000..4fd9f54fc0383d --- /dev/null +++ b/packages/expo-media-library/src/next/native/types/NativeAlbumClass.types.ts @@ -0,0 +1,19 @@ +import type { NativeAssetClass } from './NativeAssetClass.types'; + +export declare class NativeAlbumClass { + constructor(id: string); + id: string; + getAssets(): Promise; + getTitle(): Promise; + delete(): Promise; + add(assets: NativeAssetClass | NativeAssetClass[]): Promise; + removeAssets(assets: NativeAssetClass[]): Promise; + static create( + name: string, + assetsRefs: string[] | NativeAssetClass[], + moveAssets?: boolean + ): Promise; + static delete(albums: NativeAlbumClass[], deleteAssets?: boolean): Promise; + static get(title: string): Promise; + static getAll(): Promise; +} diff --git a/packages/expo-media-library/src/next/native/types/NativeAssetClass.types.ts b/packages/expo-media-library/src/next/native/types/NativeAssetClass.types.ts new file mode 100644 index 00000000000000..9758f17f43837f --- /dev/null +++ b/packages/expo-media-library/src/next/native/types/NativeAssetClass.types.ts @@ -0,0 +1,29 @@ +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { AssetInfo, Location, Shape, MediaSubtype, MediaType } from '../../types'; + +export declare class NativeAssetClass { + constructor(id: string); + id: string; + getCreationTime(): Promise; + getDuration(): Promise; + getFilename(): Promise; + getHeight(): Promise; + getMediaType(): Promise; + getMediaSubtypes(): Promise; + getLivePhotoVideoUri(): Promise; + getIsInCloud(): Promise; + getOrientation(): Promise; + getModificationTime(): Promise; + getShape(): Promise; + getUri(): Promise; + getWidth(): Promise; + getInfo(): Promise; + getAlbums(): Promise; + getLocation(): Promise; + getExif(): Promise<{ [key: string]: any }>; + delete(): Promise; + getFavorite(): Promise; + setFavorite(isFavorite: boolean): Promise; + static create(filePath: string, album?: NativeAlbumClass): Promise; + static delete(assets: NativeAssetClass[]): Promise; +} diff --git a/packages/expo-media-library/src/next/native/types/NativeMediaLibraryModuleClass.types.ts b/packages/expo-media-library/src/next/native/types/NativeMediaLibraryModuleClass.types.ts new file mode 100644 index 00000000000000..d018a0d21a36c2 --- /dev/null +++ b/packages/expo-media-library/src/next/native/types/NativeMediaLibraryModuleClass.types.ts @@ -0,0 +1,28 @@ +import type { NativeModule, PermissionResponse } from 'expo'; + +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { NativeAssetClass } from './NativeAssetClass.types'; +import type { NativeQueryClass } from './NativeQueryClass.types'; +import type { + GranularPermission, + MediaTypeFilter, + MediaLibraryAssetsChangeEvent, +} from '../../types'; + +export declare class NativeMediaLibraryModuleClass extends NativeModule<{ + mediaLibraryDidChange: (event: MediaLibraryAssetsChangeEvent) => void; +}> { + Asset: typeof NativeAssetClass; + Album: typeof NativeAlbumClass; + Query: typeof NativeQueryClass; + + getPermissionsAsync( + writeOnly?: boolean, + granularPermissions?: GranularPermission[] + ): Promise; + requestPermissionsAsync( + writeOnly?: boolean, + granularPermissions?: GranularPermission[] + ): Promise; + presentPermissionsPicker(mediaTypes?: MediaTypeFilter[]): Promise; +} diff --git a/packages/expo-media-library/src/next/native/types/NativeQueryClass.types.ts b/packages/expo-media-library/src/next/native/types/NativeQueryClass.types.ts new file mode 100644 index 00000000000000..3f19fe893c0f94 --- /dev/null +++ b/packages/expo-media-library/src/next/native/types/NativeQueryClass.types.ts @@ -0,0 +1,19 @@ +import type { NativeAlbumClass } from './NativeAlbumClass.types'; +import type { NativeAssetClass } from './NativeAssetClass.types'; +import type { AssetField, AssetFieldValueMap, AssetMetadata, SortDescriptor } from '../../types'; + +export declare class NativeQueryClass { + constructor(); + eq(field: T, value: AssetFieldValueMap[T]): NativeQueryClass; + within(field: T, value: AssetFieldValueMap[T][]): NativeQueryClass; + gt(field: AssetField, value: number): NativeQueryClass; + gte(field: AssetField, value: number): NativeQueryClass; + lt(field: AssetField, value: number): NativeQueryClass; + lte(field: AssetField, value: number): NativeQueryClass; + limit(limit: number): NativeQueryClass; + offset(offset: number): NativeQueryClass; + orderBy(sortDescriptors: SortDescriptor | AssetField): NativeQueryClass; + album(album: NativeAlbumClass): NativeQueryClass; + exe(): Promise; + exeForMetadata(): Promise; +} diff --git a/packages/expo-media-library/src/next/types/Asset.types.ts b/packages/expo-media-library/src/next/types/Asset.types.ts new file mode 100644 index 00000000000000..0b3e13d787004e --- /dev/null +++ b/packages/expo-media-library/src/next/types/Asset.types.ts @@ -0,0 +1,66 @@ +export enum MediaType { + UNKNOWN = 'unknown', + IMAGE = 'image', + AUDIO = 'audio', + VIDEO = 'video', +} + +/** + * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype). + * @platform ios + */ +export enum MediaSubtype { + DEPTH_EFFECT = 'depthEffect', + HDR = 'hdr', + HIGH_FRAME_RATE = 'highFrameRate', + LIVE_PHOTO = 'livePhoto', + PANORAMA = 'panorama', + SCREENSHOT = 'screenshot', + STREAM = 'stream', + TIME_LAPSE = 'timelapse', + SPATIAL_MEDIA = 'spatialMedia', + VIDEO_CINEMATIC = 'videoCinematic', +} + +export type Location = { + latitude: number; + longitude: number; +}; + +export type Shape = { + width: number; + height: number; +}; + +export type AssetInfo = { + id: string; + filename: string; + uri: string; + mediaType: MediaType; + width: number; + height: number; + duration: number | null; + creationTime: number | null; + modificationTime: number | null; + isFavorite?: boolean; +}; + +/** + * Lightweight metadata for a single asset, returned by [`Query.exeForMetadata`](#exeformetadata). + * + * Contains fields that can be read cheaply from the media store, without resolving file paths or + * decoding files. Use [`Asset`](#asset) getters when you need heavier fields such as URI or EXIF data. + * + * > On Android, `width` and `height` may be `null` when the media store does not record them. + */ +export type AssetMetadata = { + id: string; + filename: string | null; + mediaType: MediaType; + width: number | null; + height: number | null; + duration: number | null; + creationTime: number | null; + modificationTime: number | null; + isFavorite: boolean; +}; diff --git a/packages/expo-media-library/src/next/types/Permissions.types.ts b/packages/expo-media-library/src/next/types/Permissions.types.ts new file mode 100644 index 00000000000000..02d2490edb3aa2 --- /dev/null +++ b/packages/expo-media-library/src/next/types/Permissions.types.ts @@ -0,0 +1,10 @@ +export type GranularPermission = 'audio' | 'photo' | 'video'; + +export type MediaTypeFilter = 'photo' | 'video'; + +export { + PermissionStatus, + type PermissionExpiration, + type PermissionHookOptions, + type PermissionResponse, +} from 'expo'; diff --git a/packages/expo-media-library/src/types/AssetField.ts b/packages/expo-media-library/src/next/types/Query.types.ts similarity index 80% rename from packages/expo-media-library/src/types/AssetField.ts rename to packages/expo-media-library/src/next/types/Query.types.ts index 2209ae2bbaff82..289966f7f587cd 100644 --- a/packages/expo-media-library/src/types/AssetField.ts +++ b/packages/expo-media-library/src/next/types/Query.types.ts @@ -1,4 +1,4 @@ -import type { MediaType } from './MediaType'; +import type { MediaType } from './Asset.types'; export enum AssetField { CREATION_TIME = 'creationTime', @@ -19,3 +19,8 @@ export type AssetFieldValueMap = { [AssetField.DURATION]: number; [AssetField.IS_FAVORITE]: boolean; }; + +export type SortDescriptor = { + key: AssetField; + ascending?: boolean; +}; diff --git a/packages/expo-media-library/src/types/MediaLibraryAssetsChangeEvent.ts b/packages/expo-media-library/src/next/types/Subscriptions.types.ts similarity index 91% rename from packages/expo-media-library/src/types/MediaLibraryAssetsChangeEvent.ts rename to packages/expo-media-library/src/next/types/Subscriptions.types.ts index 4e172abcd861bc..91a0fabae49ddd 100644 --- a/packages/expo-media-library/src/types/MediaLibraryAssetsChangeEvent.ts +++ b/packages/expo-media-library/src/next/types/Subscriptions.types.ts @@ -1,3 +1,5 @@ +export { type EventSubscription, type EventSubscription as Subscription } from 'expo-modules-core'; + /** * An event emitted when assets in the media library change. */ diff --git a/packages/expo-media-library/src/next/types/index.ts b/packages/expo-media-library/src/next/types/index.ts new file mode 100644 index 00000000000000..d84707ee62aba9 --- /dev/null +++ b/packages/expo-media-library/src/next/types/index.ts @@ -0,0 +1,4 @@ +export * from './Asset.types'; +export * from './Query.types'; +export * from './Permissions.types'; +export * from './Subscriptions.types'; diff --git a/packages/expo-media-library/src/types/Asset.ts b/packages/expo-media-library/src/types/Asset.ts deleted file mode 100644 index 5f087560b9af83..00000000000000 --- a/packages/expo-media-library/src/types/Asset.ts +++ /dev/null @@ -1,237 +0,0 @@ -import type { Album } from './Album'; -import type { AssetInfo } from './AssetInfo'; -import type { Location } from './Location'; -import type { MediaSubtype } from './MediaSubtype'; -import type { MediaType } from './MediaType'; -import type { Shape } from './Shape'; - -/** - * Represents a single media asset on the device (image, video, or audio). - * - * An [Asset](#asset) instance corresponds to an entry in the device's media store. - * It exposes metadata (such as filename, dimensions, or creation time) and utility methods (like deleting). - * - * To create a new asset, use [Asset.create](#assetcreate), if you already have an asset ID, you can instantiate it directly using the constructor. - */ -export declare class Asset { - /** - * Reinitialize an instance of an asset with a given ID. - * @param id - For Android, it is a `contentUri` (content://media/external/images/media/12345) and for iOS, it is `PHAsset` localIdentifier URI. - */ - constructor(id: string); - - /** - * ID of the asset. - * Can be used to re-instantiate an [Asset](#asset) later. - * For android it is a contentUri and PHAsset localIdentifier URI for iOS. - */ - id: string; - - /** - * Gets the creation time of the asset. - * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable. - * @throws An exception if the asset could not be found. - */ - getCreationTime(): Promise; - - /** - * Gets the duration of the asset. - * Applies only to assets with media type [MediaType.audio](#mediatype) or [MediaType.video](#mediatype). - * For other media types, it returns `null`. - * @returns A promise resolving to the duration in milliseconds, or `null` if not applicable. - * @throws An exception if the asset could not be found. - */ - getDuration(): Promise; - - /** - * Gets the filename of the asset, including its extension. - * @returns A promise resolving to the filename string. - * @throws An exception if the asset could not be found. - */ - getFilename(): Promise; - - /** - * Gets the height of the asset in pixels. - * Only applicable for image and video assets. - * @returns A promise resolving to the height in pixels. - * @throws An exception if the filename cannot be found. - */ - getHeight(): Promise; - - /** - * Gets the media type of the asset (image, video, audio or unknown). - * @returns A promise resolving to a [MediaType](#mediatype) enum value. - * @throws An exception if the asset could not be found. - */ - getMediaType(): Promise; - - /** - * Gets the media subtypes of the asset, describing specific variations such as Live Photo, panorama, HDR, etc. - * @returns A promise resolving to an array of [MediaSubtype](#mediasubtype) strings. Returns an empty array if no subtypes apply. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getMediaSubtypes(): Promise; - - /** - * Gets the URI of the paired video for a Live Photo asset. - * The video is extracted to a temporary file. - * @returns A promise resolving to a `file://` URI string, or `null` if the asset is not a Live Photo. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getLivePhotoVideoUri(): Promise; - - /** - * Gets whether the asset is stored in iCloud and not available locally. - * This does not trigger a download of the asset. - * @returns A promise resolving to `true` if the asset is stored in iCloud and not available locally. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getIsInCloud(): Promise; - - /** - * Gets the EXIF display orientation of the asset. - * Only applicable for assets with media type [MediaType.image](#mediatype). - * @returns A promise resolving to a value between 1 and 8 as defined by the [EXIF orientation specification](http://sylvana.net/jpegcrop/exif_orientation.html), or `null` if unavailable. - * @throws An exception if the asset could not be found. - * @platform ios - */ - getOrientation(): Promise; - - /** - * Gets the last modification time of the asset. - * @returns A promise resolving to the UNIX timestamp in milliseconds, or `null` if unavailable. - * @throws An exception if the asset could not be found. - */ - getModificationTime(): Promise; - - /** - * Gets the shape (width and height) of the asset. - * @returns A promise resolving to the [Shape](#shape) object, or `null` if any dimension is unavailable. - * @throws An exception if the asset could not be found. - */ - getShape(): Promise; - - /** - * Gets the URI pointing to the asset’s location in the system. - * Example, for Android: `file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg`. - * @returns A promise resolving to the string URI. - * @throws An exception if the asset could not be found. - */ - getUri(): Promise; - - /** - * Gets the width of the asset in pixels. - * Only applicable for image and video assets. - * @returns A promise resolving to the width in pixels. - * @throws An exception if the asset could not be found. - */ - getWidth(): Promise; - - /** - * Gets detailed information about the asset. - * @returns A promise resolving to an [AssetInfo](#assetinfo) - * @throws An exception if the asset could not be found. - * - * > **Note:** On Android, the `isFavorite` field reflects the MediaStore `IS_FAVORITE` column, which some third-party gallery apps may not use for their own favorites. - */ - getInfo(): Promise; - - /** - * Gets the albums containing this asset. - * On Android, an asset is typically associated with a single album. - * On iOS, an asset may belong to multiple albums. - * @returns A promise resolving to an array of [Album](#album) objects. - * @throws An exception if the asset could not be found. - * - * @example - * ```ts - * const albums = await asset.getAlbums(); - * console.log(albums.length); - * ``` - */ - getAlbums(): Promise; - - /** - * Gets the location of the asset. - * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata. - * @returns A promise resolving to the [Location](#location) object or `null` if the location data is unavailable. - * @throws An exception if the asset could not be found, or if the permission is not granted on Android. - */ - getLocation(): Promise; - - /** - * Gets the exif data of the [MediaType.image](#mediatype) asset. - * On Android, this method requires the `ACCESS_MEDIA_LOCATION` permission to access location metadata. - * @returns A promise resolving to the exif data object or an empty object if the exif data is unavailable. - * @throws An exception if the asset could not be found. - */ - getExif(): Promise<{ [key: string]: any }>; - - /** - * Deletes the asset from the device’s media store. - * @returns A promise that resolves once the deletion has completed. - * - * @example - * ```ts - * await asset.delete(); - * ``` - */ - delete(): Promise; - - /** - * Gets whether the asset is marked as a favorite. - * On iOS, this checks if the asset is part of the system "Favorites" smart album. - * On Android, this reads the `IS_FAVORITE` column from MediaStore (requires Android 10+; always returns `false` on older versions). - * @returns A promise resolving to `true` if the asset is a favorite, or `false` otherwise. - * - * @example - * ```ts - * const isFavorite = await asset.getFavorite(); - * console.log(isFavorite); // true or false - * ``` - */ - getFavorite(): Promise; - - /** - * Marks or unmarks the asset as a favorite. - * On iOS, this adds or removes the asset from the system "Favorites" smart album. - * On Android, this updates the `IS_FAVORITE` column in MediaStore (requires Android 10+; no-op on older versions). - * @param isFavorite Whether the asset should be marked as favorite. - * @returns A promise that resolves once the operation has completed. - * - * > **Note:** On Android, some third-party gallery apps maintain their own favorites list and may not reflect changes made through this method. - * - * @example - * ```ts - * await asset.setFavorite(true); - * ``` - */ - setFavorite(isFavorite: boolean): Promise; - - /* - * A static function. Creates a new asset from a given file path. - * Optionally associates the asset with an album. On Android, if not specified, the asset will be placed in the default "Pictures" directory. - * - * @param filePath - Local filesystem path (for example, `file:///...`) of the file to import. - * @param album - Optional [Album](#album) instance to place the asset in. - * @returns A promise resolving to the created [Asset](#asset). - * @throws An exception if the asset could not be created, for example, if the file does not exist or permission is denied. - * - * @example - * ```ts - * const asset = await Asset.create("file:///storage/emulated/0/DCIM/Camera/IMG_20230915_123456.jpg"); - * console.log(await asset.getFilename()); // "IMG_20230915_123456.jpg" - * ``` - */ - static create(filePath: string, album?: Album): Promise; - - /** - * A static function. Deletes multiple assets from the device's media store. - * @param assets - An array of [Asset](#asset) instances to delete. - * @returns A promise that resolves once the deletion has completed. - */ - static delete(assets: Asset[]): Promise; -} diff --git a/packages/expo-media-library/src/types/AssetInfo.ts b/packages/expo-media-library/src/types/AssetInfo.ts deleted file mode 100644 index b67469e2196a02..00000000000000 --- a/packages/expo-media-library/src/types/AssetInfo.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { MediaType } from './MediaType'; - -export type AssetInfo = { - id: string; - filename: string; - uri: string; - mediaType: MediaType; - width: number; - height: number; - duration: number | null; - creationTime: number | null; - modificationTime: number | null; - isFavorite: boolean; -}; diff --git a/packages/expo-media-library/src/types/AssetMetadata.ts b/packages/expo-media-library/src/types/AssetMetadata.ts deleted file mode 100644 index aabda6f110efbb..00000000000000 --- a/packages/expo-media-library/src/types/AssetMetadata.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { MediaType } from './MediaType'; - -/** - * Lightweight metadata for a single asset, returned by [Query.exeForMetadata](#exeformetadata). - * - * Contains fields that can be read cheaply from the media store, without resolving file paths or - * decoding files. Use [Asset](#asset) getters when you need heavier fields such as URI or EXIF data. - * - * > On Android, `width` and `height` may be `null` when the media store does not record them. - */ -export type AssetMetadata = { - id: string; - filename: string | null; - mediaType: MediaType; - width: number | null; - height: number | null; - duration: number | null; - creationTime: number | null; - modificationTime: number | null; - isFavorite: boolean; -}; diff --git a/packages/expo-media-library/src/types/GranularPermission.ts b/packages/expo-media-library/src/types/GranularPermission.ts deleted file mode 100644 index e4c360d9706ee4..00000000000000 --- a/packages/expo-media-library/src/types/GranularPermission.ts +++ /dev/null @@ -1 +0,0 @@ -export type GranularPermission = 'audio' | 'photo' | 'video'; diff --git a/packages/expo-media-library/src/types/Location.ts b/packages/expo-media-library/src/types/Location.ts deleted file mode 100644 index 8fb23318a05d7b..00000000000000 --- a/packages/expo-media-library/src/types/Location.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Location = { - latitude: number; - longitude: number; -}; diff --git a/packages/expo-media-library/src/types/MediaSubtype.ts b/packages/expo-media-library/src/types/MediaSubtype.ts deleted file mode 100644 index 9b06d03741a036..00000000000000 --- a/packages/expo-media-library/src/types/MediaSubtype.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Describes specific variations of asset media. Maps to [`PHAssetMediaSubtype`](https://developer.apple.com/documentation/photokit/phassetmediasubtype). - * @platform ios - */ -export enum MediaSubtype { - DEPTH_EFFECT = 'depthEffect', - HDR = 'hdr', - HIGH_FRAME_RATE = 'highFrameRate', - LIVE_PHOTO = 'livePhoto', - PANORAMA = 'panorama', - SCREENSHOT = 'screenshot', - STREAM = 'stream', - TIME_LAPSE = 'timelapse', - SPATIAL_MEDIA = 'spatialMedia', - VIDEO_CINEMATIC = 'videoCinematic', -} diff --git a/packages/expo-media-library/src/types/MediaType.ts b/packages/expo-media-library/src/types/MediaType.ts deleted file mode 100644 index 566ae3f241df8e..00000000000000 --- a/packages/expo-media-library/src/types/MediaType.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum MediaType { - UNKNOWN = 'unknown', - IMAGE = 'image', - AUDIO = 'audio', - VIDEO = 'video', -} diff --git a/packages/expo-media-library/src/types/MediaTypeFilter.ts b/packages/expo-media-library/src/types/MediaTypeFilter.ts deleted file mode 100644 index bd9b00f1071a8c..00000000000000 --- a/packages/expo-media-library/src/types/MediaTypeFilter.ts +++ /dev/null @@ -1 +0,0 @@ -export type MediaTypeFilter = 'photo' | 'video'; diff --git a/packages/expo-media-library/src/types/Shape.ts b/packages/expo-media-library/src/types/Shape.ts deleted file mode 100644 index d16b7f9684b939..00000000000000 --- a/packages/expo-media-library/src/types/Shape.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type Shape = { - width: number; - height: number; -}; diff --git a/packages/expo-media-library/src/types/SortDescriptor.ts b/packages/expo-media-library/src/types/SortDescriptor.ts deleted file mode 100644 index 48eae255b97640..00000000000000 --- a/packages/expo-media-library/src/types/SortDescriptor.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { AssetField } from './AssetField'; - -export type SortDescriptor = { - key: AssetField; - ascending?: boolean; -}; diff --git a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt index 9a0dd66aa11ac5..3806cca9e5a30c 100644 --- a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt +++ b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/ExpoAutolinkingPlugin.kt @@ -10,10 +10,8 @@ import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.file.Directory -import org.gradle.api.file.RegularFile import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider -import java.nio.file.Paths const val generatedPackageListNamespace = "expo.modules" const val generatedPackageListFilename = "ExpoModulesPackageList.kt" @@ -44,31 +42,6 @@ open class ExpoAutolinkingPlugin : Plugin { project.logger.quiet(" - ${subproject.name.withColor(Colors.GREEN)} (${subproject.version})") } - project.gradle.projectsEvaluated { - val srcDir = project.file("src/main/java/inline/modules/").absolutePath - val buildDir = project.file("build/inline/modules/").absolutePath - val nodeWorkingDir = project.rootProject.projectDir - val watchedDirectoriesSerialized = project.findProperty("expo.inlineModules.watchedDirectories") ?: emptyList() - - project.providers.exec { spec -> - spec.workingDir(nodeWorkingDir) - spec.commandLine( - "node", - "--no-warnings", - "--eval", - "require('expo/bin/autolinking')", - "expo-modules-autolinking", - "mirror-kotlin-inline-modules", - "--kotlin-files-mirror-directory", - srcDir, - "--inline-modules-list-directory", - buildDir, - "--watched-directories-serialized", - watchedDirectoriesSerialized - ) - }.standardOutput.asText.get() -} - prebuiltProjects.forEach { prebuiltProject -> val publication = requireNotNull(prebuiltProject.publication) project.dependencies.add("api", "${publication.groupId}:${publication.artifactId}:${publication.version}") @@ -78,21 +51,38 @@ open class ExpoAutolinkingPlugin : Plugin { project.logger.quiet("") - // Creates a task that generates a list of expo modules. + // Creates the tasks that generate the expo module package list and the inline modules list. val generatePackagesList = createGeneratePackagesListTask(project, gradleExtension.config.modules, gradleExtension.hash) + val generateInlineModules = createGenerateInlineModulesTask(project) - // Ensures that the task is executed before the build. + // Ensures the generators run before the build. project.tasks .named("preBuild", Task::class.java) - .configure { it.dependsOn(generatePackagesList) } - - // Adds the generated file to the source set. - project.extensions.getByType(AndroidComponentsExtension::class.java).finalizeDsl { ext -> - ext - .sourceSets - .getByName("main") - .java - .srcDirs(getPackageListDir(project), getInlineModulesDir(project)) + .configure { it.dependsOn(generatePackagesList, generateInlineModules) } + + // Registers the generated sources. The right mechanism differs by AGP version: + // - AGP 9 disallows Provider instances in the legacy SourceSet API and only compiles .kt from + // the variant `kotlin` sources, so use the Variant Sources API + // - AGP 8 does not expose `variant.sources.kotlin`, so fall back to the legacy source set + val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java) + if (androidComponents.pluginVersion.major >= 9) { + androidComponents.onVariants { variant -> + @Suppress("UnstableApiUsage") + val kotlinSource = requireNotNull(variant.sources.kotlin) { "Can't access kotlin source sets" } + + with(kotlinSource) { + addGeneratedSourceDirectory(generatePackagesList) { it.outputDirectory } + addGeneratedSourceDirectory(generateInlineModules) { it.outputDirectory } + } + } + } else { + androidComponents.finalizeDsl { ext -> + ext + .sourceSets + .getByName("main") + .java + .srcDirs(getPackageListDir(project), getInlineModulesDir(project)) + } } } @@ -104,24 +94,27 @@ open class ExpoAutolinkingPlugin : Plugin { return project.layout.buildDirectory.dir("inline/modules") } - fun getPackageListFile(project: Project): Provider { - val packageListRelativePath = Paths.get( - generatedFilesSrcDir, - generatedPackageListNamespace.replace('.', '/'), - generatedPackageListFilename - ).toString() - return project.layout.buildDirectory.file(packageListRelativePath) - } - fun createGeneratePackagesListTask(project: Project, modules: List, hash: String): TaskProvider { return project.tasks.register("generatePackagesList", GeneratePackagesListTask::class.java) { it.hash.set(hash) it.namespace.set(generatedPackageListNamespace) - it.outputFile.set(getPackageListFile(project)) + it.outputDirectory.set(getPackageListDir(project)) it.modules = modules } } + fun createGenerateInlineModulesTask(project: Project): TaskProvider { + return project.tasks.register("generateInlineModules", GenerateInlineModulesTask::class.java) { + it.nodeWorkingDir.set(project.rootProject.layout.projectDirectory) + it.mirrorDirectory.set(project.layout.projectDirectory.dir("src/main/java/inline/modules")) + it.outputDirectory.set(getInlineModulesDir(project)) + it.watchedDirectoriesSerialized.set( + (project.findProperty("expo.inlineModules.watchedDirectories") + ?: emptyList()).toString() + ) + } + } + private fun findAppProject(root: Project): Project? { return root.allprojects.firstOrNull { it.plugins.hasPlugin("com.android.application") } } diff --git a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GenerateInlineModulesTask.kt b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GenerateInlineModulesTask.kt new file mode 100644 index 00000000000000..b6820230ef7bda --- /dev/null +++ b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GenerateInlineModulesTask.kt @@ -0,0 +1,73 @@ +package expo.modules.plugin + +import org.gradle.api.DefaultTask +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory +import org.gradle.api.tasks.TaskAction +import org.gradle.process.ExecOperations +import javax.inject.Inject + +/** + * Task that mirrors the Kotlin inline modules and generates the `ExpoInlineModulesList` provider. + */ +abstract class GenerateInlineModulesTask : DefaultTask() { + init { + group = "expo" + // Inline modules can change between builds, so always regenerate. + outputs.upToDateWhen { false } + } + + /** + * Working directory used to resolve the `expo-modules-autolinking` node command (the root project). + */ + @get:Internal + abstract val nodeWorkingDir: DirectoryProperty + + /** + * Directory the inline Kotlin module files are mirrored into. This lives under `src` (a regular + * source directory that is compiled without any extra registration), so it is not a tracked + * output of this task. + */ + @get:Internal + abstract val mirrorDirectory: DirectoryProperty + + /** + * Serialized list of the directories watched for inline modules. + */ + @get:Input + abstract val watchedDirectoriesSerialized: Property + + /** + * Output directory (a generated source root) where `ExpoInlineModulesList.kt` is written. Only + * this directory is wired with `addGeneratedSourceDirectory`. + */ + @get:OutputDirectory + abstract val outputDirectory: DirectoryProperty + + @get:Inject + abstract val execOperations: ExecOperations + + @TaskAction + fun generateInlineModules() { + execOperations.exec { spec -> + spec.workingDir(nodeWorkingDir.get().asFile) + spec.commandLine( + "node", + "--no-warnings", + "--eval", + "require('expo/bin/autolinking')", + "expo-modules-autolinking", + "mirror-kotlin-inline-modules", + "--kotlin-files-mirror-directory", + mirrorDirectory.get().asFile.absolutePath, + "--inline-modules-list-directory", + outputDirectory.get().asFile.absolutePath, + "--watched-directories-serialized", + watchedDirectoriesSerialized.get() + ) + } + } +} diff --git a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GeneratePackagesListTask.kt b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GeneratePackagesListTask.kt index d79a614a5646fa..bca18682b9d9bb 100644 --- a/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GeneratePackagesListTask.kt +++ b/packages/expo-modules-autolinking/android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GeneratePackagesListTask.kt @@ -2,11 +2,11 @@ package expo.modules.plugin import expo.modules.plugin.configuration.ExpoModule import org.gradle.api.DefaultTask -import org.gradle.api.file.RegularFileProperty +import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction /** @@ -38,17 +38,18 @@ abstract class GeneratePackagesListTask : DefaultTask() { lateinit var modules: List /** - * The output file where the package list should be written. + * The output directory where the package list should be written. */ - @get:OutputFile - abstract val outputFile: RegularFileProperty + @get:OutputDirectory + abstract val outputDirectory: DirectoryProperty @TaskAction fun generatePackagesList() { - val target = outputFile.get().asFile - val content = generatePackageListFileContent() - - target.writeText(content) + val target = outputDirectory.get().asFile + .resolve(namespace.get().replace('.', '/')) + .resolve(generatedPackageListFilename) + target.parentFile.mkdirs() + target.writeText(generatePackageListFileContent()) } private fun generatePackageListFileContent(): String { diff --git a/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js b/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js index 1b939db289ab01..f0398c31975a45 100644 --- a/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js +++ b/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js @@ -32,37 +32,27 @@ function getClassName(classNameWithPackage) { return classNameWithPackage.substring(index + 1); } async function generateInlineModulesListFile(inlineModulesListPath, inlineModulesMirror) { - const fileContent = `package inline.modules; + const fileContent = `package inline.modules -import org.jetbrains.annotations.NotNull; +import expo.modules.kotlin.ModulesProvider +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.services.Service -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import expo.modules.kotlin.ModulesProvider; -import expo.modules.kotlin.modules.Module; -import expo.modules.kotlin.services.Service; - -public class ExpoInlineModulesList implements ModulesProvider { - - @Override - public Map, String> getModulesMap() { - return Map.of( +class ExpoInlineModulesList : ModulesProvider { + override fun getModulesMap(): Map, String?> { + return mapOf( ${inlineModulesMirror.kotlinClasses - .map((moduleClass) => ` ${moduleClass}.class, "${getClassName(moduleClass)}"`) + .map((moduleClass) => ` ${moduleClass}::class.java to "${getClassName(moduleClass)}"`) .join(',\n')} - ); + ) } - @Override - public List> getServices() { - return new ArrayList<>(); + override fun getServices(): List> { + return emptyList() } } - `; await fs_1.default.promises.mkdir(inlineModulesListPath, { recursive: true }); - await fs_1.default.promises.writeFile(path_1.default.resolve(inlineModulesListPath, 'ExpoInlineModulesList.java'), fileContent); + await fs_1.default.promises.writeFile(path_1.default.resolve(inlineModulesListPath, 'ExpoInlineModulesList.kt'), fileContent); } //# sourceMappingURL=androidInlineModules.js.map \ No newline at end of file diff --git a/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js.map b/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js.map index 40dd4759681a5e..13e46db34212b4 100644 --- a/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js.map +++ b/packages/expo-modules-autolinking/build/inlineModules/androidInlineModules.js.map @@ -1 +1 @@ -{"version":3,"file":"androidInlineModules.js","sourceRoot":"","sources":["../../src/inlineModules/androidInlineModules.ts"],"names":[],"mappings":";;;;;AAOA,kEAiBC;AAED,oCAMC;AAED,sEAwCC;AA1ED,qCAAgC;AAChC,4CAAoB;AACpB,gDAAwB;AAGxB,gDAAyC;AAElC,KAAK,UAAU,2BAA2B,CAC/C,UAAkB,EAClB,mBAAwC;IAExC,MAAM,WAAW,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAEjG,MAAM,IAAA,qBAAO,EAAC,WAAW,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QAC5D,MAAM,4BAA4B,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzE,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;QAE1E,IAAI,CAAC;YACH,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvE,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAA,eAAK,EAAC,mCAAmC,QAAQ,YAAY,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,YAAY,CAAC,oBAA4B;IACvD,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IACD,OAAO,oBAAoB,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC;AAEM,KAAK,UAAU,6BAA6B,CACjD,qBAA6B,EAC7B,mBAAwC;IAExC,MAAM,WAAW,GAAG;;;;;;;;;;;;;;;;;EAiBpB,mBAAmB,CAAC,aAAa;SAChC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,SAAS,WAAW,YAAY,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC;SAClF,IAAI,CAAC,KAAK,CAAC;;;;;;;;;;CAUb,CAAC;IAEA,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,4BAA4B,CAAC,EACjE,WAAW,CACZ,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"androidInlineModules.js","sourceRoot":"","sources":["../../src/inlineModules/androidInlineModules.ts"],"names":[],"mappings":";;;;;AAOA,kEAiBC;AAED,oCAMC;AAED,sEA8BC;AAhED,qCAAgC;AAChC,4CAAoB;AACpB,gDAAwB;AAGxB,gDAAyC;AAElC,KAAK,UAAU,2BAA2B,CAC/C,UAAkB,EAClB,mBAAwC;IAExC,MAAM,WAAW,GAAG,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAEjG,MAAM,IAAA,qBAAO,EAAC,WAAW,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;QAC5D,MAAM,4BAA4B,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzE,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,UAAU,EAAE,4BAA4B,CAAC,CAAC;QAE1E,IAAI,CAAC;YACH,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvE,MAAM,YAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAA,eAAK,EAAC,mCAAmC,QAAQ,YAAY,CAAC,EAAE,CAAC,CAAC;QACpE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,YAAY,CAAC,oBAA4B;IACvD,MAAM,KAAK,GAAG,oBAAoB,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpD,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IACD,OAAO,oBAAoB,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC;AAEM,KAAK,UAAU,6BAA6B,CACjD,qBAA6B,EAC7B,mBAAwC;IAExC,MAAM,WAAW,GAAG;;;;;;;;;EASpB,mBAAmB,CAAC,aAAa;SAChC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,SAAS,WAAW,oBAAoB,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC;SAC1F,IAAI,CAAC,KAAK,CAAC;;;;;;;;CAQb,CAAC;IAEA,MAAM,YAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,YAAE,CAAC,QAAQ,CAAC,SAAS,CACzB,cAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,0BAA0B,CAAC,EAC/D,WAAW,CACZ,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts b/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts index 6dc11bfcf0f5a7..1a419474d3b0e4 100644 --- a/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts +++ b/packages/expo-modules-autolinking/src/__tests__/inlineModules.test.ts @@ -255,14 +255,14 @@ describe('androidInlineModules.ts', () => { await generateInlineModulesListFile(listPath, mockMirror); - const targetFile = '/build/generated/ExpoInlineModulesList.java'; + const targetFile = '/build/generated/ExpoInlineModulesList.kt'; expect(fs.existsSync(targetFile)).toBe(true); const content = await fs.promises.readFile(targetFile, 'utf8'); - expect(content).toContain('some.simple.package.SimpleModule.class, "SimpleModule"'); - expect(content).toContain('other.package.SimpleView.class, "SimpleView"'); + expect(content).toContain('some.simple.package.SimpleModule::class.java to "SimpleModule"'); + expect(content).toContain('other.package.SimpleView::class.java to "SimpleView"'); }); }); }); diff --git a/packages/expo-modules-autolinking/src/inlineModules/androidInlineModules.ts b/packages/expo-modules-autolinking/src/inlineModules/androidInlineModules.ts index 77953df0606857..54ac3748c08a1f 100644 --- a/packages/expo-modules-autolinking/src/inlineModules/androidInlineModules.ts +++ b/packages/expo-modules-autolinking/src/inlineModules/androidInlineModules.ts @@ -36,40 +36,30 @@ export async function generateInlineModulesListFile( inlineModulesListPath: string, inlineModulesMirror: InlineModulesMirror ) { - const fileContent = `package inline.modules; + const fileContent = `package inline.modules -import org.jetbrains.annotations.NotNull; +import expo.modules.kotlin.ModulesProvider +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.services.Service -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import expo.modules.kotlin.ModulesProvider; -import expo.modules.kotlin.modules.Module; -import expo.modules.kotlin.services.Service; - -public class ExpoInlineModulesList implements ModulesProvider { - - @Override - public Map, String> getModulesMap() { - return Map.of( +class ExpoInlineModulesList : ModulesProvider { + override fun getModulesMap(): Map, String?> { + return mapOf( ${inlineModulesMirror.kotlinClasses - .map((moduleClass) => ` ${moduleClass}.class, "${getClassName(moduleClass)}"`) + .map((moduleClass) => ` ${moduleClass}::class.java to "${getClassName(moduleClass)}"`) .join(',\n')} - ); + ) } - @Override - public List> getServices() { - return new ArrayList<>(); + override fun getServices(): List> { + return emptyList() } } - `; await fs.promises.mkdir(inlineModulesListPath, { recursive: true }); await fs.promises.writeFile( - path.resolve(inlineModulesListPath, 'ExpoInlineModulesList.java'), + path.resolve(inlineModulesListPath, 'ExpoInlineModulesList.kt'), fileContent ); } diff --git a/packages/expo-observe/ios/CursorRepair.swift b/packages/expo-observe/ios/CursorRepair.swift index 1922d15169b302..dcdbc4e6d6d85b 100644 --- a/packages/expo-observe/ios/CursorRepair.swift +++ b/packages/expo-observe/ios/CursorRepair.swift @@ -2,17 +2,15 @@ import ExpoAppMetrics -/** - Resets a dispatch cursor to `-1` if it has fallen past the largest id currently in its source - table. The cursors live in UserDefaults; their source tables can be wiped from underneath them - (notably on a schema-version mismatch in `expo-app-metrics`). Without this check the cursor would - skip every new row until enough accumulated to pass the stale value. - - - `signalName`: short human-readable label ("metric" / "log") for log messages. - - `readCursor`: returns the persisted cursor value. - - `writeCursor`: persists a new cursor value. - - `readMaxId`: returns the largest id in the source table, or nil when empty. - */ +/// Resets a dispatch cursor to `-1` if it has fallen past the largest id currently in its source +/// table. The cursors live in UserDefaults; their source tables can be wiped from underneath them +/// (notably on a schema-version mismatch in `expo-app-metrics`). Without this check the cursor would +/// skip every new row until enough accumulated to pass the stale value. +/// +/// - `signalName`: short human-readable label ("metric" / "log") for log messages. +/// - `readCursor`: returns the persisted cursor value. +/// - `writeCursor`: persists a new cursor value. +/// - `readMaxId`: returns the largest id in the source table, or nil when empty. @AppMetricsActor internal func repairCursorIfStale( signalName: String, @@ -25,11 +23,14 @@ internal func repairCursorIfStale( do { maxId = try readMaxId() } catch { - observeLogger.warn("[Observe] Failed to read max \(signalName) id while repairing cursor: \(error.localizedDescription)") + observeLogger.warn( + "[Observe] Failed to read max \(signalName) id while repairing cursor: \(error.localizedDescription)") return } if cursor > (maxId ?? -1) { - observeLogger.info("[Observe] Resetting stale \(signalName) dispatch cursor (was \(cursor), max id is \(maxId.map(String.init) ?? ""))") + observeLogger.info( + "[Observe] Resetting stale \(signalName) dispatch cursor (was \(cursor), max id is \(maxId.map(String.init) ?? ""))" + ) writeCursor(-1) } } diff --git a/packages/expo-observe/ios/Event.swift b/packages/expo-observe/ios/Event.swift index bcb8b493f42899..afc96d1c8269b9 100644 --- a/packages/expo-observe/ios/Event.swift +++ b/packages/expo-observe/ios/Event.swift @@ -2,10 +2,8 @@ import ExpoAppMetrics import ExpoModulesCore import Foundation -/** - An object representing an event providing some app metrics and the information about the app and the device. - In this form metrics and metadata are sent to the EAS endpoint. - */ +/// An object representing an event providing some app metrics and the information about the app and the device. +/// In this form metrics and metadata are sent to the EAS endpoint. struct Event: Codable, Sendable { let metadata: Metadata let metrics: [Metric] @@ -65,11 +63,9 @@ struct Event: Codable, Sendable { let sessionId: String } - /** - Builds an `Event` from a session row plus its metric/log batch. The session row carries all the - metadata that used to live on `Entry`/`AppInfo`/`DeviceInfo`; metrics and logs are passed - separately so a partial dispatch (only the rows past a cursor) can still produce a valid event. - */ + /// Builds an `Event` from a session row plus its metric/log batch. The session row carries all the + /// metadata that used to live on `Entry`/`AppInfo`/`DeviceInfo`; metrics and logs are passed + /// separately so a partial dispatch (only the rows past a cursor) can still produce a valid event. static func from(session: SessionRow, metrics: [MetricRow], logs: [LogRow]) -> Event { let updatesInfo = AppInfo.UpdatesInfo( updateId: session.appUpdateId, diff --git a/packages/expo-observe/ios/Observability.swift b/packages/expo-observe/ios/Observability.swift index 012d4d4658015f..a9c944db1268c9 100644 --- a/packages/expo-observe/ios/Observability.swift +++ b/packages/expo-observe/ios/Observability.swift @@ -119,11 +119,9 @@ internal struct ObservabilityManager { } } - /** - Groups `metrics` by `sessionId`, hydrates the matching session rows, and emits one `Event` per - session in the same shape Android dispatches: each event carries the session's metadata and only - the metrics that belong to it. - */ + /// Groups `metrics` by `sessionId`, hydrates the matching session rows, and emits one `Event` per + /// session in the same shape Android dispatches: each event carries the session's metadata and only + /// the metrics that belong to it. private static func buildEvents(forMetrics metrics: [MetricRow]) throws -> [Event] { let metricsBySession = Dictionary(grouping: metrics, by: \.sessionId) let sessionIds = Array(metricsBySession.keys) @@ -158,7 +156,7 @@ internal struct ObservabilityManager { // (we control that endpoint, so the harmless overhead is fine). The name is duplicated here // rather than imported: expo-observe must not depend on expo-app-metrics internals. Keep it // in sync with `NetworkRequestURLProtocol.internalHeaderName` in expo-app-metrics. - "Expo-AppMetrics-Skip": "1" + "Expo-AppMetrics-Skip": "1", ] request.httpBody = try body.toJSONData([]) @@ -175,10 +173,14 @@ internal struct ObservabilityManager { return false } guard (200...299).contains(urlResponse.statusCode) else { - observeLogger.warn("[EAS Observe] Server responded with \(urlResponse.statusCode) status code and data: \(String(data: responseData, encoding: .utf8) ?? "")") + observeLogger.warn( + "[EAS Observe] Server responded with \(urlResponse.statusCode) status code and data: \(String(data: responseData, encoding: .utf8) ?? "")" + ) return false } - observeLogger.debug("[EAS Observe] Server responded successfully with \(urlResponse.statusCode) status code and data: \(String(data: responseData, encoding: .utf8) ?? "")") + observeLogger.debug( + "[EAS Observe] Server responded successfully with \(urlResponse.statusCode) status code and data: \(String(data: responseData, encoding: .utf8) ?? "")" + ) return true } @@ -233,4 +235,3 @@ internal struct ObservabilityManager { return EASClientID.deterministicUniformValue(EASClientID.uuid()) < clamped } } - diff --git a/packages/expo-observe/ios/ObserveAppDelegateSubscriber.swift b/packages/expo-observe/ios/ObserveAppDelegateSubscriber.swift index d6aa6a704e2233..262558c63e4f8c 100644 --- a/packages/expo-observe/ios/ObserveAppDelegateSubscriber.swift +++ b/packages/expo-observe/ios/ObserveAppDelegateSubscriber.swift @@ -1,7 +1,7 @@ // Copyright 2025-present 650 Industries. All rights reserved. -import ExpoModulesCore import ExpoAppMetrics +import ExpoModulesCore public class ObserveAppDelegateSubscriber: ExpoAppDelegateSubscriber { public func applicationWillResignActive(_ application: UIApplication) { diff --git a/packages/expo-observe/ios/ObserveModule.swift b/packages/expo-observe/ios/ObserveModule.swift index bc8f20717f6ff2..a07a25bbd68874 100644 --- a/packages/expo-observe/ios/ObserveModule.swift +++ b/packages/expo-observe/ios/ObserveModule.swift @@ -1,7 +1,7 @@ // Copyright 2025-present 650 Industries. All rights reserved. -import ExpoModulesCore import ExpoAppMetrics +import ExpoModulesCore internal let observeLogger = Logger(logHandlers: [createOSLogHandler(category: Logger.EXPO_LOG_CATEGORY)]) @@ -57,8 +57,8 @@ public final class ObserveModule: Module { Function("setBundleDefaults") { (defaults: BundleDefaults) in guard !defaults.environment.isEmpty else { observeLogger.warn( - "[EAS Observe] setBundleDefaults received empty environment; skipping. " + - "This is a bug in the JS layer — `process.env.NODE_ENV` should always resolve." + "[EAS Observe] setBundleDefaults received empty environment; skipping. " + + "This is a bug in the JS layer — `process.env.NODE_ENV` should always resolve." ) return } @@ -97,10 +97,8 @@ private func getUseOpenTelemetry(_ manifest: [String: Any]) -> Bool? { return getManifestProperty("extra.eas.observe.useOpenTelemetry", manifest) as? Bool } -/** - * Traverses the manifest using a dot-separated property chain. - * For example, "extra.eas.projectId" will navigate manifest["extra"]["eas"]["projectId"]. - */ +/// Traverses the manifest using a dot-separated property chain. +/// For example, "extra.eas.projectId" will navigate manifest["extra"]["eas"]["projectId"]. private func getManifestProperty(_ propertyChain: String, _ manifest: [String: Any]) -> Any? { let keys = propertyChain.split(separator: ".").map { String($0) } var value: Any? = manifest diff --git a/packages/expo-observe/ios/ObserveUserDefaults.swift b/packages/expo-observe/ios/ObserveUserDefaults.swift index 75d0d3ccbd3d84..724996318ee23b 100644 --- a/packages/expo-observe/ios/ObserveUserDefaults.swift +++ b/packages/expo-observe/ios/ObserveUserDefaults.swift @@ -2,38 +2,28 @@ import ExpoAppMetrics -/** - Snapshot of the last `configure(...)` payload. - */ +/// Snapshot of the last `configure(...)` payload. internal struct PersistedConfig: Codable { var dispatchingEnabled: Bool? var dispatchInDebug: Bool? var sampleRate: Double? } -/** - Bundle-derived facts pushed from the JS layer at package import time. - - Set atomically by `setBundleDefaults`. - */ +/// Bundle-derived facts pushed from the JS layer at package import time. +/// +/// Set atomically by `setBundleDefaults`. internal struct PersistedBundleDefaults: Codable { var environment: String var isJsDev: Bool } -/** - Class that manages a custom `UserDefaults` database with `"dev.expo.observe"` suite name. - */ +/// Class that manages a custom `UserDefaults` database with `"dev.expo.observe"` suite name. @AppMetricsActor internal final class ObserveUserDefaults: UserDefaults { - /** - Singleton instance of the user defaults for EAS Observe. - */ + /// Singleton instance of the user defaults for EAS Observe. private static let defaults = ObserveUserDefaults() - /** - Enum with keys used within this user defaults database. - */ + /// Enum with keys used within this user defaults database. private enum Keys: String { case lastDispatchedMetricId case lastDispatchedLogId @@ -48,9 +38,7 @@ internal final class ObserveUserDefaults: UserDefaults { super.init(suiteName: "dev.expo.observe")! } - /** - Date when events with metrics were last sent and received by the backend. - */ + /// Date when events with metrics were last sent and received by the backend. static var lastDispatchDate: Date? { get { if let dateString = defaults.string(forKey: Keys.lastDispatchDate.rawValue) { @@ -64,11 +52,9 @@ internal final class ObserveUserDefaults: UserDefaults { } } - /** - Id of the last metric row dispatched. Each successful dispatch advances this past the largest id - in the batch so the next dispatch reads only newer rows. Auto-increment ids are monotonic in - SQLite, so a date-independent cursor avoids drift when the device clock changes. - */ + /// Id of the last metric row dispatched. Each successful dispatch advances this past the largest id + /// in the batch so the next dispatch reads only newer rows. Auto-increment ids are monotonic in + /// SQLite, so a date-independent cursor avoids drift when the device clock changes. static var lastDispatchedMetricId: Int64 { get { return (defaults.object(forKey: Keys.lastDispatchedMetricId.rawValue) as? Int64) ?? -1 @@ -78,10 +64,8 @@ internal final class ObserveUserDefaults: UserDefaults { } } - /** - Id of the last log row dispatched. Tracked separately from the metric cursor so a logs request - failure does not block metrics dispatch (and vice versa) — both signals move forward independently. - */ + /// Id of the last log row dispatched. Tracked separately from the metric cursor so a logs request + /// failure does not block metrics dispatch (and vice versa) — both signals move forward independently. static var lastDispatchedLogId: Int64 { get { return (defaults.object(forKey: Keys.lastDispatchedLogId.rawValue) as? Int64) ?? -1 diff --git a/packages/expo-observe/ios/OpenTelemetry.swift b/packages/expo-observe/ios/OpenTelemetry.swift index 6080f5d36bc442..55accbccfe580f 100644 --- a/packages/expo-observe/ios/OpenTelemetry.swift +++ b/packages/expo-observe/ios/OpenTelemetry.swift @@ -1,5 +1,5 @@ -import Foundation import ExpoAppMetrics +import Foundation // MARK: -- Open Telemetry data classes @@ -7,11 +7,9 @@ struct OTStringValue: Codable, Sendable { let stringValue: String } -/** - Tagged union mirroring the OTLP `AnyValue` shape — encodes as an object with - exactly one of `stringValue` / `intValue` / `doubleValue` / `boolValue` / - `arrayValue` / `kvlistValue`, depending on the variant. - */ +/// Tagged union mirroring the OTLP `AnyValue` shape — encodes as an object with +/// exactly one of `stringValue` / `intValue` / `doubleValue` / `boolValue` / +/// `arrayValue` / `kvlistValue`, depending on the variant. enum OTAnyValue: Codable, Sendable { case string(String) case int(Int64) @@ -68,24 +66,18 @@ enum OTAnyValue: Codable, Sendable { } } -/** - Inner `arrayValue` shape per the OTLP spec — wraps `values: [AnyValue]`. - */ +/// Inner `arrayValue` shape per the OTLP spec — wraps `values: [AnyValue]`. struct OTArrayValue: Codable, Sendable { let values: [OTAnyValue] } -/** - Inner `kvlistValue` shape per the OTLP spec — wraps `values: [KeyValue]`. - */ +/// Inner `kvlistValue` shape per the OTLP spec — wraps `values: [KeyValue]`. struct OTKeyValueList: Codable, Sendable { let values: [OTKeyValue] } -/** - Key/value pair used inside `kvlistValue` (and at the top level for span - attributes). Same shape as `OTAttribute` but split out for the recursive case. - */ +/// Key/value pair used inside `kvlistValue` (and at the top level for span +/// attributes). Same shape as `OTAttribute` but split out for the recursive case. struct OTKeyValue: Codable, Sendable { let key: String let value: OTAnyValue @@ -165,16 +157,14 @@ struct OTResourceLogs: Codable, Sendable { // MARK: -- Event extensions for Open Telemetry -/** - OpenTelemetry Semantic Conventions schema URL referenced by the resource on - every dispatched payload. Bumping this constant signals that our attribute - names follow a newer revision of the conventions. - - Before bumping, audit the attribute keys we set in `toOTMetadata` and - `toOTLogRecord` against the SemConv changelog at - https://github.com/open-telemetry/semantic-conventions/blob/main/CHANGELOG.md - — a renamed key would silently mismatch the declared schema otherwise. - */ +/// OpenTelemetry Semantic Conventions schema URL referenced by the resource on +/// every dispatched payload. Bumping this constant signals that our attribute +/// names follow a newer revision of the conventions. +/// +/// Before bumping, audit the attribute keys we set in `toOTMetadata` and +/// `toOTLogRecord` against the SemConv changelog at +/// https://github.com/open-telemetry/semantic-conventions/blob/main/CHANGELOG.md +/// — a renamed key would silently mismatch the declared schema otherwise. private let semConvSchemaUrl = "https://opentelemetry.io/schemas/1.27.0" // This must be kept in sync with the INTERNAL_TO_OTEL map in universe @@ -207,7 +197,8 @@ nonisolated(unsafe) let formatter = ISO8601DateFormatter() private func nsFromISOString(_ dateString: String?) -> UInt64 { if let dateString, - let date = formatter.date(from: dateString) { + let date = formatter.date(from: dateString) + { return UInt64(date.timeIntervalSince1970 * 1_000_000_000) } return UInt64(Date().timeIntervalSince1970 * 1_000_000_000) @@ -251,7 +242,7 @@ extension Event.Log { func toOTLogRecord() -> OTLogRecord { var attributes: [OTAttribute] = [ OTAttribute(key: "session.id", rawValue: sessionId), - OTAttribute(key: "event.name", rawValue: name) + OTAttribute(key: "event.name", rawValue: name), ] var encodeTimeDrops = 0 @@ -275,12 +266,10 @@ extension Event.Log { } } -/** - Maps a caller-supplied attribute dictionary to typed `OTAttribute`s. Returns the - mapped attributes plus a count of entries that could not be represented (a - value type we don't support, or a deeply unrepresentable nested structure) so - the caller can fold them into the OTel `droppedAttributesCount`. - */ +/// Maps a caller-supplied attribute dictionary to typed `OTAttribute`s. Returns the +/// mapped attributes plus a count of entries that could not be represented (a +/// value type we don't support, or a deeply unrepresentable nested structure) so +/// the caller can fold them into the OTel `droppedAttributesCount`. func otAttributesFromUserDict(_ dict: [String: Any]) -> (attributes: [OTAttribute], droppedCount: Int) { var attributes: [OTAttribute] = [] var droppedCount = 0 @@ -294,14 +283,12 @@ func otAttributesFromUserDict(_ dict: [String: Any]) -> (attributes: [OTAttribut return (attributes, droppedCount) } -/** - Converts an arbitrary `Any` value coming from the JS bridge (or the AnyCodable - storage roundtrip) into an `OTAnyValue`. Returns `nil` for values whose type - cannot be expressed in OTLP — callers should treat these as dropped attributes. - - Booleans must be tested before integers because `Bool` bridges to `NSNumber` - and would otherwise be matched as `Int` first. - */ +/// Converts an arbitrary `Any` value coming from the JS bridge (or the AnyCodable +/// storage roundtrip) into an `OTAnyValue`. Returns `nil` for values whose type +/// cannot be expressed in OTLP — callers should treat these as dropped attributes. +/// +/// Booleans must be tested before integers because `Bool` bridges to `NSNumber` +/// and would otherwise be matched as `Int` first. func otAnyValue(from value: Any) -> OTAnyValue? { // `as? Bool` succeeds for any NSNumber holding 0 or 1 — including `Int(0)` / `Int(1)` from JS, // which would otherwise quietly emit as `boolValue` instead of `intValue`. Distinguish real @@ -412,7 +399,7 @@ extension Event { scopeMetrics: [ OTScopeMetrics( scope: OTScope(name: "expo-observe", version: ObserveVersions.clientVersion), - metrics: self.metrics.map{ $0.toOTMetric() } + metrics: self.metrics.map { $0.toOTMetric() } ) ], schemaUrl: semConvSchemaUrl diff --git a/packages/expo-observe/ios/RequestBody.swift b/packages/expo-observe/ios/RequestBody.swift index 7829ab87fc9b3a..53e13f9b3f5311 100644 --- a/packages/expo-observe/ios/RequestBody.swift +++ b/packages/expo-observe/ios/RequestBody.swift @@ -1,8 +1,6 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Body of the request containing events with metrics for the EAS server. - */ +/// Body of the request containing events with metrics for the EAS server. internal struct RequestBody: Codable, Sendable { let easClientId: String let events: [Event] diff --git a/packages/expo-observe/ios/RequestResponse.swift b/packages/expo-observe/ios/RequestResponse.swift index 0ca59b4abb08d0..668156e35ef98e 100644 --- a/packages/expo-observe/ios/RequestResponse.swift +++ b/packages/expo-observe/ios/RequestResponse.swift @@ -1,8 +1,6 @@ // Copyright 2025-present 650 Industries. All rights reserved. -/** - Represents the response from the EAS server, if the request was successful. - */ +/// Represents the response from the EAS server, if the request was successful. internal struct RequestResponse: Codable { let eventsProcessed: Int let metricsInserted: Int diff --git a/packages/expo-observe/ios/Tests/CursorRepairTests.swift b/packages/expo-observe/ios/Tests/CursorRepairTests.swift index 37bd77afa92151..310ab5abe6d79f 100644 --- a/packages/expo-observe/ios/Tests/CursorRepairTests.swift +++ b/packages/expo-observe/ios/Tests/CursorRepairTests.swift @@ -65,7 +65,10 @@ struct CursorRepairTests { repairCursorIfStale( signalName: "metric", readCursor: { stored }, - writeCursor: { stored = $0; writeCalled = true }, + writeCursor: { + stored = $0 + writeCalled = true + }, readMaxId: { nil } ) #expect(stored == -1) @@ -81,7 +84,10 @@ struct CursorRepairTests { repairCursorIfStale( signalName: "metric", readCursor: { stored }, - writeCursor: { stored = $0; writeCalled = true }, + writeCursor: { + stored = $0 + writeCalled = true + }, readMaxId: { throw CursorRepairTestsError.boom } ) #expect(stored == 42) diff --git a/packages/expo-observe/ios/Tests/OTAnyValueTests.swift b/packages/expo-observe/ios/Tests/OTAnyValueTests.swift index 875f7e112f1151..57da500ce653ad 100644 --- a/packages/expo-observe/ios/Tests/OTAnyValueTests.swift +++ b/packages/expo-observe/ios/Tests/OTAnyValueTests.swift @@ -243,10 +243,11 @@ struct OTAnyValueCodableTests { @Test func `encodes .kvlist as kvlistValue.values with key/value pairs`() throws { - let json = try encode(.kvlist([ - OTKeyValue(key: "a", value: .int(1)), - OTKeyValue(key: "b", value: .string("x")) - ])) + let json = try encode( + .kvlist([ + OTKeyValue(key: "a", value: .int(1)), + OTKeyValue(key: "b", value: .string("x")), + ])) #expect(json.count == 1) let kvlistValue = try #require(json["kvlistValue"] as? [String: Any]) let values = try #require(kvlistValue["values"] as? [[String: Any]]) @@ -263,7 +264,7 @@ struct OTAnyValueCodableTests { OTKeyValue(key: "count", value: .int(3)), OTKeyValue(key: "ratio", value: .double(0.5)), OTKeyValue(key: "ok", value: .bool(true)), - OTKeyValue(key: "tags", value: .array([.string("a"), .string("b")])) + OTKeyValue(key: "tags", value: .array([.string("a"), .string("b")])), ]) let data = try JSONEncoder().encode(original) let decoded = try JSONDecoder().decode(OTAnyValue.self, from: data) diff --git a/packages/expo-observe/ios/Tests/ObserveUserDefaultsTests.swift b/packages/expo-observe/ios/Tests/ObserveUserDefaultsTests.swift index eb4bbd9fd6cf03..9c14131b5e6f4d 100644 --- a/packages/expo-observe/ios/Tests/ObserveUserDefaultsTests.swift +++ b/packages/expo-observe/ios/Tests/ObserveUserDefaultsTests.swift @@ -1,7 +1,7 @@ +import ExpoAppMetrics import Testing @testable import ExpoObserve -import ExpoAppMetrics @AppMetricsActor @Suite("ObserveUserDefaults", .serialized) diff --git a/packages/expo-observe/ios/Tests/OpenTelemetryTests.swift b/packages/expo-observe/ios/Tests/OpenTelemetryTests.swift index 82e9865158d626..f9db011f8347d9 100644 --- a/packages/expo-observe/ios/Tests/OpenTelemetryTests.swift +++ b/packages/expo-observe/ios/Tests/OpenTelemetryTests.swift @@ -1,7 +1,7 @@ import Testing -@testable import ExpoObserve @testable import ExpoAppMetrics +@testable import ExpoObserve @Suite("OpenTelemetry conversion") struct OpenTelemetryTests { @@ -144,7 +144,7 @@ struct OpenTelemetryTests { let metric = makeMetric(name: "loadTime", value: 1.0, timestamp: "2026-01-09T12:08:09Z") let otMetric = metric.toOTMetric() - let expectedNanos: UInt64 = 1767960489 * 1_000_000_000 + let expectedNanos: UInt64 = 1_767_960_489 * 1_000_000_000 #expect(otMetric.gauge.dataPoints[0].timeUnixNano == expectedNanos) } @@ -308,7 +308,8 @@ struct OpenTelemetryTests { customParams: nil ) let otMetric = metric.toOTMetric() - let attrs = Dictionary(uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) + let attrs = Dictionary( + uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) #expect(attrs["expo.route_name"] == "/home") } @@ -327,7 +328,8 @@ struct OpenTelemetryTests { customParams: nil ) let otMetric = metric.toOTMetric() - let attrs = Dictionary(uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) + let attrs = Dictionary( + uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) #expect(otMetric.name == "expo.updates.download_time") #expect(attrs["expo.update_id"] == "abc123-def456") @@ -366,7 +368,8 @@ struct OpenTelemetryTests { customParams: AnyCodable(["screen": "dashboard", "variant": "A"] as [String: Any]) ) let otMetric = metric.toOTMetric() - let attrs = Dictionary(uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) + let attrs = Dictionary( + uniqueKeysWithValues: otMetric.gauge.dataPoints[0].attributes.map { ($0.key, $0.value.stringValue) }) let jsonString = try #require(attrs["expo.custom_params"] ?? nil) let parsed = try! JSONSerialization.jsonObject(with: jsonString.data(using: .utf8)!) as! [String: String] @@ -400,7 +403,7 @@ struct OpenTelemetryTests { let requestBody = OTRequestBody(resourceMetrics: [ event1.toOTEvent(testEasClientId), - event2.toOTEvent(testEasClientId) + event2.toOTEvent(testEasClientId), ]) #expect(requestBody.resourceMetrics.count == 2) @@ -409,13 +412,11 @@ struct OpenTelemetryTests { } } -/** - Test-only convenience for pulling the inner string out of an `OTAnyValue`. - Returns `nil` for non-string variants — the metric tests in this file only - produce string-valued attributes, so a nil result is a real assertion failure. - */ -private extension OTAnyValue { - var stringValue: String? { +/// Test-only convenience for pulling the inner string out of an `OTAnyValue`. +/// Returns `nil` for non-string variants — the metric tests in this file only +/// produce string-valued attributes, so a nil result is a real assertion failure. +extension OTAnyValue { + fileprivate var stringValue: String? { if case .string(let value) = self { return value } diff --git a/packages/expo-observe/package.json b/packages/expo-observe/package.json index f32a59c9cd26b2..cdf9dbda1c0a4d 100644 --- a/packages/expo-observe/package.json +++ b/packages/expo-observe/package.json @@ -21,6 +21,8 @@ "build": "expo-module build", "clean": "expo-module clean", "lint": "expo-module lint", + "swift:format": "../../scripts/swift-format.sh", + "swift:lint": "../../scripts/swift-format.sh --lint", "test": "expo-module test", "prepublishOnly": "expo-module prepublishOnly", "expo-module": "expo-module" diff --git a/packages/expo-router/package.json b/packages/expo-router/package.json index e82429d328016c..b936d6e4b10dda 100644 --- a/packages/expo-router/package.json +++ b/packages/expo-router/package.json @@ -140,7 +140,7 @@ "@types/react-test-renderer": "^19.1.0", "expo": "workspace:*", "immer": "^10.1.1", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-reanimated": "~4.3.1", "react-native-safe-area-context": "~5.6.2", "react-native-screens": "^4.25.2", diff --git a/packages/expo-ui/CHANGELOG.md b/packages/expo-ui/CHANGELOG.md index 6c48a49783e211..021544d1168ef8 100644 --- a/packages/expo-ui/CHANGELOG.md +++ b/packages/expo-ui/CHANGELOG.md @@ -33,6 +33,7 @@ ### 🐛 Bug fixes +- [android] Fix React Native `Pressable`/`Button` taps not registering on `community/pager-view` pages after the first on physical devices. ([#46851](https://github.com/expo/expo/pull/46851) by [@nishan](https://github.com/intergalacticspacehighway)) - [universal] Fix user-supplied `modifiers` having no effect when the component derives a modifier of the same type from its props, e.g. `buttonStyle` on `Button` always losing to the `variant` prop. ([#46815](https://github.com/expo/expo/pull/46815) by [@nishan](https://github.com/intergalacticspacehighway)) - [android] Fix race between JS imperative `expand()` and Compose handler registration on `ModalBottomSheet`. Adds `initialFullyExpanded` prop to drive initial snap state natively. ([#46367](https://github.com/expo/expo/pull/46367) by [@duyanhv](https://github.com/duyanhv)) - [iOS][android] Fix `community/bottom-sheet` blocking touches behind the sheet after it's dismissed. ([#46805](https://github.com/expo/expo/pull/46805) by [@nishan](https://github.com/intergalacticspacehighway)) diff --git a/packages/expo-ui/build/community/pager-view/PagerView.android.d.ts.map b/packages/expo-ui/build/community/pager-view/PagerView.android.d.ts.map index 1288f5a97018ea..90b87cbc4c982c 100644 --- a/packages/expo-ui/build/community/pager-view/PagerView.android.d.ts.map +++ b/packages/expo-ui/build/community/pager-view/PagerView.android.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"PagerView.android.d.ts","sourceRoot":"","sources":["../../../src/community/pager-view/PagerView.android.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAO/D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,2CA0H9C"} \ No newline at end of file +{"version":3,"file":"PagerView.android.d.ts","sourceRoot":"","sources":["../../../src/community/pager-view/PagerView.android.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAO/D;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,2CA8H9C"} \ No newline at end of file diff --git a/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts b/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts index 481b0af1295553..65cc722a444d6a 100644 --- a/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts +++ b/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts @@ -1,4 +1,5 @@ import type { ReactElement } from 'react'; +import type { StyleProp, ViewStyle } from 'react-native'; import type { ModifierConfig } from '../../types'; import type { PrimitiveBaseProps } from '../layout'; export interface RNHostProps extends PrimitiveBaseProps { @@ -17,6 +18,13 @@ export interface RNHostProps extends PrimitiveBaseProps { * Modifiers for the component. */ modifiers?: ModifierConfig[]; + /** + * Style applied to the host view's React Native shadow node. Useful for + * controlling its layout position (e.g. `position: 'absolute'`) so the shadow + * layout matches where the hosting Compose component draws the content — + * important for `measure()`-based hit-testing such as `Pressable`. + */ + style?: StyleProp; } export declare function RNHostView(props: RNHostProps): import("react/jsx-runtime").JSX.Element; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts.map b/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts.map index 4a40965b1046f3..6d128a4e220dd7 100644 --- a/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts.map +++ b/packages/expo-ui/build/jetpack-compose/RNHostView/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jetpack-compose/RNHostView/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,WAAW,WAAY,SAAQ,kBAAkB;IACrD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;CAC9B;AAiBD,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,2CAS5C"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/jetpack-compose/RNHostView/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAiB,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,WAAW,WAAY,SAAQ,kBAAkB;IACrD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B;AAiBD,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,2CAS5C"} \ No newline at end of file diff --git a/packages/expo-ui/src/community/pager-view/PagerView.android.tsx b/packages/expo-ui/src/community/pager-view/PagerView.android.tsx index f39a04f97c3063..d17714f9ad93ca 100644 --- a/packages/expo-ui/src/community/pager-view/PagerView.android.tsx +++ b/packages/expo-ui/src/community/pager-view/PagerView.android.tsx @@ -43,11 +43,9 @@ export function PagerView(props: PagerViewProps) { setScrollEnabledState(scrollEnabled); }, [scrollEnabled]); - // All pages share the same (0,0) origin in RN's layout — Compose, not Yoga, - // applies the per-page offset — so off-screen pages overlap the visible one in - // RN's coordinate space and can steal its touches (#46386). Track the settled - // page and make only it interactive; non-settled pages are `pointerEvents` - // "none" so hit-testing resolves taps to the page actually on screen. + // The pages overlap (see the absolute positioning below), so gate touches to + // the settled page; the rest are `pointerEvents="none"` so taps resolve to the + // page on screen (#46386). const [settledPage, setSettledPage] = useState(initialPage); // Synthesize pager-view's `idle | dragging | settling` from Compose's raw @@ -79,7 +77,13 @@ export function PagerView(props: PagerViewProps) { const pages = Children.toArray(children) .filter((child): child is ReactElement => isValidElement(child)) .map((child, index) => ( - + {child} diff --git a/packages/expo-ui/src/jetpack-compose/RNHostView/index.tsx b/packages/expo-ui/src/jetpack-compose/RNHostView/index.tsx index 5ad680404095c9..b3b52eb0308136 100644 --- a/packages/expo-ui/src/jetpack-compose/RNHostView/index.tsx +++ b/packages/expo-ui/src/jetpack-compose/RNHostView/index.tsx @@ -1,5 +1,6 @@ import { requireNativeView } from 'expo'; import type { ReactElement, ComponentType } from 'react'; +import type { StyleProp, ViewStyle } from 'react-native'; import type { ModifierConfig } from '../../types'; import type { PrimitiveBaseProps } from '../layout'; @@ -21,6 +22,13 @@ export interface RNHostProps extends PrimitiveBaseProps { * Modifiers for the component. */ modifiers?: ModifierConfig[]; + /** + * Style applied to the host view's React Native shadow node. Useful for + * controlling its layout position (e.g. `position: 'absolute'`) so the shadow + * layout matches where the hosting Compose component draws the content — + * important for `measure()`-based hit-testing such as `Pressable`. + */ + style?: StyleProp; } type NativeRNHostProps = RNHostProps; diff --git a/packages/expo/CHANGELOG.md b/packages/expo/CHANGELOG.md index 7284aa8d986947..197653431b52d6 100644 --- a/packages/expo/CHANGELOG.md +++ b/packages/expo/CHANGELOG.md @@ -15,6 +15,7 @@ - Fix `bodyUsed` leaking across siblings when fetch Response is cloned twice ([#46397](https://github.com/expo/expo/pull/46397) by [@zoontek](https://github.com/zoontek)) - Prevent fatal `The stream is not in a state that permits close` in `expo/fetch` when native delivers `didComplete`/`didFailWithError` after the consumer has already canceled the body stream. ([#44909](https://github.com/expo/expo/pull/44909) by [@safaiyeh](https://github.com/safaiyeh)) - Adopted the UIKit scene-based life cycle on iOS so apps built with the iOS 27 SDK launch correctly. ([#46733](https://github.com/expo/expo/pull/46733) by [@alanjhughes](https://github.com/alanjhughes)) +- [iOS] Mark `ExpoAppSceneDelegate` as unavailable in extensions. ([#46799](https://github.com/expo/expo/pull/46799) by [@jakex7](https://github.com/jakex7)) ### 💡 Others diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index 7eac089c0bcf83..253a9f8f87c376 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -100,7 +100,7 @@ "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", "react-native-web": "~0.21.0", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-get-random-values": "~1.11.0", "react-native-keyboard-controller": "1.21.9", "react-native-maps": "1.27.2", diff --git a/packages/expo/ios/AppDelegates/ExpoAppSceneDelegate.swift b/packages/expo/ios/AppDelegates/ExpoAppSceneDelegate.swift index e014ccd673c9ee..3c7355a63e8410 100644 --- a/packages/expo/ios/AppDelegates/ExpoAppSceneDelegate.swift +++ b/packages/expo/ios/AppDelegates/ExpoAppSceneDelegate.swift @@ -15,6 +15,7 @@ import React - Re-feed scene life-cycle, URL, and user-activity events to the existing `ExpoAppDelegateSubscriberManager`, so app delegate subscribers keep working unchanged. */ +@available(iOSApplicationExtension, unavailable) @objc(EXExpoAppSceneDelegate) open class ExpoAppSceneDelegate: UIResponder, UIWindowSceneDelegate { open var window: UIWindow? diff --git a/patches/react-native-gesture-handler.patch b/patches/react-native-gesture-handler.patch deleted file mode 100644 index fb913c3037e0fd..00000000000000 --- a/patches/react-native-gesture-handler.patch +++ /dev/null @@ -1,291 +0,0 @@ -diff --git a/lib/commonjs/RNRenderer.js b/lib/commonjs/RNRenderer.js -deleted file mode 100644 -index 7845103a88ce49f6cef0f68a904974c0f84da645..0000000000000000000000000000000000000000 -diff --git a/lib/commonjs/RNRenderer.web.js b/lib/commonjs/RNRenderer.web.js -deleted file mode 100644 -index a94a363d11db1fe2f104d4950aa1748496d4f295..0000000000000000000000000000000000000000 -diff --git a/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js b/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js -index 27a4164f4082a465709f7d20e8d80c9e49bf849e..cda7cb38e79e6bc67d1e1341ad77196752d73c20 100644 ---- a/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js -+++ b/lib/commonjs/handlers/gestures/GestureDetector/useDetectorUpdater.js -@@ -24,7 +24,6 @@ function useDetectorUpdater(state, preparedGesture, gesturesToAttach, gestureCon - const viewTag = (0, _findNodeHandle.default)(state.viewRef); - const didUnderlyingViewChange = viewTag !== state.previousViewTag; - if (didUnderlyingViewChange || (0, _needsToReattach.needsToReattach)(preparedGesture, gesturesToAttach)) { -- (0, _utils.validateDetectorChildren)(state.viewRef); - (0, _dropHandlers.dropHandlers)(preparedGesture); - (0, _attachHandlers.attachHandlers)({ - preparedGesture, -diff --git a/lib/commonjs/handlers/gestures/GestureDetector/utils.js b/lib/commonjs/handlers/gestures/GestureDetector/utils.js -index 28412d948d51b46566ad0fc97049603b79b81200..78c565caac91da4f773a2baf371d6da9b7045d66 100644 ---- a/lib/commonjs/handlers/gestures/GestureDetector/utils.js -+++ b/lib/commonjs/handlers/gestures/GestureDetector/utils.js -@@ -8,8 +8,6 @@ exports.checkGestureCallbacksForWorklets = checkGestureCallbacksForWorklets; - exports.extractGestureRelations = extractGestureRelations; - exports.useForceRender = useForceRender; - exports.useWebEventHandlers = useWebEventHandlers; --exports.validateDetectorChildren = validateDetectorChildren; --var _reactNative = require("react-native"); - var _utils = require("../../../utils"); - var _gesture = require("../gesture"); - var _FlingGestureHandler = require("../../FlingGestureHandler"); -@@ -21,7 +19,6 @@ var _hoverGesture = require("../hoverGesture"); - var _NativeViewGestureHandler = require("../../NativeViewGestureHandler"); - var _gestureHandlerCommon = require("../../gestureHandlerCommon"); - var _EnableNewWebImplementation = require("../../../EnableNewWebImplementation"); --var _RNRenderer = require("../../../RNRenderer"); - var _react = require("react"); - var _reanimatedWrapper = require("../reanimatedWrapper"); - var _eventReceiver = require("../eventReceiver"); -@@ -88,51 +85,6 @@ function checkGestureCallbacksForWorklets(gesture) { - console.warn((0, _utils.tagMessage)(`None of the callbacks in the gesture are worklets. If you wish to run them on the JS thread use '.runOnJS(true)' modifier on the gesture to make this explicit. Otherwise, mark the callbacks as 'worklet' to run them on the UI thread.`)); - } - } -- --// eslint-disable-next-line @typescript-eslint/no-explicit-any --function validateDetectorChildren(ref) { -- // Finds the first native view under the Wrap component and traverses the fiber tree upwards -- // to check whether there is more than one native view as a pseudo-direct child of GestureDetector -- // i.e. this is not ok: -- // Wrap -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- // -- // but this is fine: -- // Wrap -- // | -- // NativeView -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- if (__DEV__ && _reactNative.Platform.OS !== 'web') { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- const wrapType = -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ref._reactInternals.elementType; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- let instance = _RNRenderer.RNRenderer.findHostInstance_DEPRECATED(ref)._internalFiberInstanceHandleDEV; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- while (instance && instance.elementType !== wrapType) { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- if (instance.sibling) { -- throw new Error('GestureDetector has more than one native view as its children. This can happen if you are using a custom component that renders multiple views, like React.Fragment. You should wrap content of GestureDetector with a or .'); -- } -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access -- instance = instance.return; -- } -- } --} - function useForceRender() { - const [renderState, setRenderState] = (0, _react.useState)(false); - const forceRender = (0, _react.useCallback)(() => { -diff --git a/lib/module/RNRenderer.js b/lib/module/RNRenderer.js -deleted file mode 100644 -index be7999d6237748e3834183835c3e2a064841c8db..0000000000000000000000000000000000000000 -diff --git a/lib/module/RNRenderer.web.js b/lib/module/RNRenderer.web.js -deleted file mode 100644 -index 5d9872ab168754600944fad432f278bb674ccaa6..0000000000000000000000000000000000000000 -diff --git a/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js b/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js -index c8e3ae2f4924b3ecf7b117914b502f995b8dd2fb..1fd877a6adf77ed17edbe79c301eda553c4a2c45 100644 ---- a/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js -+++ b/lib/module/handlers/gestures/GestureDetector/useDetectorUpdater.js -@@ -5,7 +5,7 @@ import { attachHandlers } from './attachHandlers'; - import { updateHandlers } from './updateHandlers'; - import { needsToReattach } from './needsToReattach'; - import { dropHandlers } from './dropHandlers'; --import { useForceRender, validateDetectorChildren } from './utils'; -+import { useForceRender } from './utils'; - import findNodeHandle from '../../../findNodeHandle'; - - // Returns a function that's responsible for updating the attached gestures -@@ -20,7 +20,6 @@ export function useDetectorUpdater(state, preparedGesture, gesturesToAttach, ges - const viewTag = findNodeHandle(state.viewRef); - const didUnderlyingViewChange = viewTag !== state.previousViewTag; - if (didUnderlyingViewChange || needsToReattach(preparedGesture, gesturesToAttach)) { -- validateDetectorChildren(state.viewRef); - dropHandlers(preparedGesture); - attachHandlers({ - preparedGesture, -diff --git a/lib/module/handlers/gestures/GestureDetector/utils.js b/lib/module/handlers/gestures/GestureDetector/utils.js -index 9c752528da231b78c8bf0a37bf5885b47434755c..587dee50386d5459332a2955b071ed83b32202d5 100644 ---- a/lib/module/handlers/gestures/GestureDetector/utils.js -+++ b/lib/module/handlers/gestures/GestureDetector/utils.js -@@ -1,6 +1,5 @@ - "use strict"; - --import { Platform } from 'react-native'; - import { isTestEnv, tagMessage } from '../../../utils'; - import { BaseGesture } from '../gesture'; - import { flingGestureHandlerProps } from '../../FlingGestureHandler'; -@@ -12,7 +11,6 @@ import { hoverGestureHandlerProps } from '../hoverGesture'; - import { nativeViewGestureHandlerProps } from '../../NativeViewGestureHandler'; - import { baseGestureHandlerWithDetectorProps } from '../../gestureHandlerCommon'; - import { isNewWebImplementationEnabled } from '../../../EnableNewWebImplementation'; --import { RNRenderer } from '../../../RNRenderer'; - import { useCallback, useRef, useState } from 'react'; - import { Reanimated } from '../reanimatedWrapper'; - import { onGestureHandlerEvent } from '../eventReceiver'; -@@ -79,51 +77,6 @@ export function checkGestureCallbacksForWorklets(gesture) { - console.warn(tagMessage(`None of the callbacks in the gesture are worklets. If you wish to run them on the JS thread use '.runOnJS(true)' modifier on the gesture to make this explicit. Otherwise, mark the callbacks as 'worklet' to run them on the UI thread.`)); - } - } -- --// eslint-disable-next-line @typescript-eslint/no-explicit-any --export function validateDetectorChildren(ref) { -- // Finds the first native view under the Wrap component and traverses the fiber tree upwards -- // to check whether there is more than one native view as a pseudo-direct child of GestureDetector -- // i.e. this is not ok: -- // Wrap -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- // -- // but this is fine: -- // Wrap -- // | -- // NativeView -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- if (__DEV__ && Platform.OS !== 'web') { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- const wrapType = -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ref._reactInternals.elementType; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- let instance = RNRenderer.findHostInstance_DEPRECATED(ref)._internalFiberInstanceHandleDEV; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- while (instance && instance.elementType !== wrapType) { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- if (instance.sibling) { -- throw new Error('GestureDetector has more than one native view as its children. This can happen if you are using a custom component that renders multiple views, like React.Fragment. You should wrap content of GestureDetector with a or .'); -- } -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access -- instance = instance.return; -- } -- } --} - export function useForceRender() { - const [renderState, setRenderState] = useState(false); - const forceRender = useCallback(() => { -diff --git a/src/RNRenderer.ts b/src/RNRenderer.ts -deleted file mode 100644 -index 7a585b64c0bc7167718e187e96b29ad8c7cbff17..0000000000000000000000000000000000000000 -diff --git a/src/RNRenderer.web.ts b/src/RNRenderer.web.ts -deleted file mode 100644 -index d46b825958bf5123babebee49ea95664fbe6af43..0000000000000000000000000000000000000000 -diff --git a/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts b/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts -index d6d82c4b70c781732831d12815d84e2ac685478e..34fc83d99b39ec6df9fd002bb7121c6c348dffec 100644 ---- a/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts -+++ b/src/handlers/gestures/GestureDetector/useDetectorUpdater.ts -@@ -11,7 +11,7 @@ import { attachHandlers } from './attachHandlers'; - import { updateHandlers } from './updateHandlers'; - import { needsToReattach } from './needsToReattach'; - import { dropHandlers } from './dropHandlers'; --import { useForceRender, validateDetectorChildren } from './utils'; -+import { useForceRender } from './utils'; - import findNodeHandle from '../../../findNodeHandle'; - - // Returns a function that's responsible for updating the attached gestures -@@ -36,7 +36,6 @@ export function useDetectorUpdater( - didUnderlyingViewChange || - needsToReattach(preparedGesture, gesturesToAttach) - ) { -- validateDetectorChildren(state.viewRef); - dropHandlers(preparedGesture); - attachHandlers({ - preparedGesture, -diff --git a/src/handlers/gestures/GestureDetector/utils.ts b/src/handlers/gestures/GestureDetector/utils.ts -index fc713189b2e3401df7054b0495649b290743987f..9f9f20a6fbeb38df966848a4bf071dca305108aa 100644 ---- a/src/handlers/gestures/GestureDetector/utils.ts -+++ b/src/handlers/gestures/GestureDetector/utils.ts -@@ -1,5 +1,3 @@ --import { Platform } from 'react-native'; -- - import { isTestEnv, tagMessage } from '../../../utils'; - import { GestureRef, BaseGesture, GestureType } from '../gesture'; - -@@ -18,7 +16,6 @@ import { - baseGestureHandlerWithDetectorProps, - } from '../../gestureHandlerCommon'; - import { isNewWebImplementationEnabled } from '../../../EnableNewWebImplementation'; --import { RNRenderer } from '../../../RNRenderer'; - import { useCallback, useRef, useState } from 'react'; - import { Reanimated } from '../reanimatedWrapper'; - import { onGestureHandlerEvent } from '../eventReceiver'; -@@ -124,56 +121,6 @@ export function checkGestureCallbacksForWorklets(gesture: GestureType) { - } - } - --// eslint-disable-next-line @typescript-eslint/no-explicit-any --export function validateDetectorChildren(ref: any) { -- // Finds the first native view under the Wrap component and traverses the fiber tree upwards -- // to check whether there is more than one native view as a pseudo-direct child of GestureDetector -- // i.e. this is not ok: -- // Wrap -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- // -- // but this is fine: -- // Wrap -- // | -- // NativeView -- // | -- // / \ -- // / \ -- // / \ -- // / \ -- // NativeView NativeView -- if (__DEV__ && Platform.OS !== 'web') { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- const wrapType = -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ref._reactInternals.elementType; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- let instance = -- RNRenderer.findHostInstance_DEPRECATED( -- ref -- )._internalFiberInstanceHandleDEV; -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- while (instance && instance.elementType !== wrapType) { -- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- if (instance.sibling) { -- throw new Error( -- 'GestureDetector has more than one native view as its children. This can happen if you are using a custom component that renders multiple views, like React.Fragment. You should wrap content of GestureDetector with a or .' -- ); -- } -- -- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access -- instance = instance.return; -- } -- } --} -- - export function useForceRender() { - const [renderState, setRenderState] = useState(false); - const forceRender = useCallback(() => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bbe77bda9d591d..1c40a2b15e8d4e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,9 +19,6 @@ patchedDependencies: '@shopify/react-native-skia@2.6.2': hash: ba884424a75156115606f768b005e5af9a39e9836f1acbc8e70c5d2fd5d13044 path: patches/@shopify__react-native-skia@2.6.2.patch - react-native-gesture-handler: - hash: e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b - path: patches/react-native-gesture-handler.patch react-native-reanimated: hash: 1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138 path: patches/react-native-reanimated.patch @@ -218,8 +215,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-keyboard-controller: specifier: ^1.21.9 version: 1.21.9(react-native-reanimated@4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -385,8 +382,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: specifier: ~4.3.1 version: 4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -651,8 +648,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-keyboard-controller: specifier: ^1.21.9 version: 1.21.9(react-native-reanimated@4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -820,7 +817,7 @@ importers: version: 7.15.5(b7e4a390cd4ad54d20d8e7f5fba586f7) '@react-navigation/drawer': specifier: ^7.9.4 - version: 7.9.4(88472275b2def517d1c20a016e21c5d8) + version: 7.9.4(9edaf5d89b26b780525c5bb1dc18f7dd) '@react-navigation/elements': specifier: ^2.9.10 version: 2.9.10(e4f1fd64f869a5116075efc9f2099688) @@ -832,7 +829,7 @@ importers: version: 7.14.5(b7e4a390cd4ad54d20d8e7f5fba586f7) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(fd409fa481ee955177d6f1ffa958d5c6) + version: 7.8.5(dacdb47ddb7ebe8a25b6a2ebb2cd937e) '@shopify/flash-list': specifier: 2.0.2 version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1113,8 +1110,8 @@ importers: specifier: ^5.3.0 version: 5.4.6(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-keyboard-controller: specifier: ^1.21.9 version: 1.21.9(react-native-reanimated@4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1313,8 +1310,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: specifier: 4.3.0 version: 4.3.0(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1498,8 +1495,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-pager-view: specifier: ^8.0.2 version: 8.0.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -1609,7 +1606,7 @@ importers: version: 7.14.5(770a97769f92f824806f4d75d3b1de80) '@react-navigation/stack': specifier: ^7.8.5 - version: 7.8.5(f970542fab7c1f326f624c15fd5bc520) + version: 7.8.5(6f78bac5e4abc4926ac1582f1f172865) async-retry: specifier: ^1.1.4 version: 1.3.3 @@ -1791,8 +1788,8 @@ importers: specifier: 0.86.0-rc.3 version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: specifier: ^5.6.2 version: 5.6.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -5229,7 +5226,7 @@ importers: version: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) react-native-drawer-layout: specifier: ^4.2.2 - version: 4.2.2(f4d17243775763f60b61bc9c88a3eb4a) + version: 4.2.2(7857da294e059d0720b234e2ed922734) react-native-screens: specifier: ^4.25.2 version: 4.25.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -5295,8 +5292,8 @@ importers: specifier: ^10.1.1 version: 10.2.0 react-native-gesture-handler: - specifier: ~2.31.2 - version: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + specifier: ~2.32.0 + version: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: specifier: ~4.3.1 version: 4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -7973,72 +7970,85 @@ packages: resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.1.0': resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.1.0': resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.1.0': resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.1.0': resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.1.0': resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.1.0': resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.2': resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.2': resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.2': resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.2': resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.2': resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.2': resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.2': resolution: {integrity: sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==} @@ -8384,36 +8394,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -9028,24 +9044,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.18': resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.15.18': resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.18': resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.18': resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==} @@ -9666,41 +9686,49 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -12862,24 +12890,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} @@ -14177,8 +14209,8 @@ packages: react: '*' react-native: 0.86.0-rc.3 - react-native-gesture-handler@2.31.2: - resolution: {integrity: sha512-rw5q74i2AfS7YGYdbxQDhOU7xqgY6WRM1132/CCm3erqjblhECZDZFHIm0tteHoC9ih24wogVBVVzcTBQtZ+5A==} + react-native-gesture-handler@2.32.0: + resolution: {integrity: sha512-uYIMOKlKENORq2SABE+jIjbPU+h5I/sQKcq2v16zRq848nwEp1fWRVwML4QWqijc8UcXJC25o54S8GQd4Mf2OA==} peerDependencies: react: '*' react-native: 0.86.0-rc.3 @@ -18938,15 +18970,15 @@ snapshots: use-latest-callback: 0.2.6(react@19.2.3) use-sync-external-store: 1.6.0(react@19.2.3) - '@react-navigation/drawer@7.9.4(88472275b2def517d1c20a016e21c5d8)': + '@react-navigation/drawer@7.9.4(9edaf5d89b26b780525c5bb1dc18f7dd)': dependencies: '@react-navigation/elements': 2.9.10(e4f1fd64f869a5116075efc9f2099688) '@react-navigation/native': 7.1.33(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) color: 4.2.3 react: 19.2.3 react-native: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) - react-native-drawer-layout: 4.2.2(f4d17243775763f60b61bc9c88a3eb4a) - react-native-gesture-handler: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-drawer-layout: 4.2.2(7857da294e059d0720b234e2ed922734) + react-native-gesture-handler: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: 4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.7.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: 4.25.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) @@ -19020,28 +19052,28 @@ snapshots: dependencies: nanoid: 3.3.11 - '@react-navigation/stack@7.8.5(f970542fab7c1f326f624c15fd5bc520)': + '@react-navigation/stack@7.8.5(6f78bac5e4abc4926ac1582f1f172865)': dependencies: '@react-navigation/elements': 2.9.10(b54486e859f70f4df22fdedfc74caa43) '@react-navigation/native': 7.1.33(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) color: 4.2.3 react: 19.2.3 react-native: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) - react-native-gesture-handler: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-gesture-handler: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.6.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: 4.25.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/stack@7.8.5(fd409fa481ee955177d6f1ffa958d5c6)': + '@react-navigation/stack@7.8.5(dacdb47ddb7ebe8a25b6a2ebb2cd937e)': dependencies: '@react-navigation/elements': 2.9.10(e4f1fd64f869a5116075efc9f2099688) '@react-navigation/native': 7.1.33(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) color: 4.2.3 react: 19.2.3 react-native: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) - react-native-gesture-handler: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-gesture-handler: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-safe-area-context: 5.7.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-screens: 4.25.2(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) @@ -25138,12 +25170,12 @@ snapshots: react-is@19.2.4: {} - react-native-drawer-layout@4.2.2(f4d17243775763f60b61bc9c88a3eb4a): + react-native-drawer-layout@4.2.2(7857da294e059d0720b234e2ed922734): dependencies: color: 4.2.3 react: 19.2.3 react-native: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) - react-native-gesture-handler: 2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) + react-native-gesture-handler: 2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) react-native-reanimated: 4.3.1(patch_hash=1e34e4238541638db96b94d5a2e974e73f3b801788a3d8f5c3f4b237a0559138)(react-native-worklets@0.8.3(patch_hash=3f49a21b44ba558989a3366eeff9c92ee331e18b736dbe89c5962ecc6f2802f1)(@babel/core@7.29.0)(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3))(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3) use-latest-callback: 0.2.6(react@19.2.3) @@ -25152,7 +25184,7 @@ snapshots: react: 19.2.3 react-native: 0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3) - react-native-gesture-handler@2.31.2(patch_hash=e8fb2a67f1fa221dc758c27292b3ee21ed7371780ae9c9905d80ad94ca0c329b)(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): + react-native-gesture-handler@2.32.0(react-native@0.86.0-rc.3(@babel/core@7.29.0)(@react-native/jest-preset@0.86.0-rc.3(@babel/core@7.29.0)(react@19.2.3))(@react-native/metro-config@0.86.0-rc.3(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.3))(react@19.2.3): dependencies: '@egjs/hammerjs': 2.0.17 '@types/react-test-renderer': 19.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ef7eadca635e35..be54451f9ae5ca 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -31,7 +31,6 @@ onlyBuiltDependencies: patchedDependencies: '@react-native-community/netinfo': patches/@react-native-community+netinfo.patch '@shopify/react-native-skia@2.6.2': patches/@shopify__react-native-skia@2.6.2.patch - react-native-gesture-handler: patches/react-native-gesture-handler.patch react-native-reanimated: patches/react-native-reanimated.patch react-native-view-shot: patches/react-native-view-shot.patch react-native-worklets: patches/react-native-worklets.patch @@ -46,6 +45,7 @@ minimumReleaseAgeExclude: - '@react-native/*' - 'react-native' - multitars + - 'react-native-gesture-handler' - 'react-native-reanimated' - 'react-native-screens' - 'whatwg-url-minimum' diff --git a/templates/expo-template-default/package.json b/templates/expo-template-default/package.json index 99ec0f7496f901..898f775c317619 100644 --- a/templates/expo-template-default/package.json +++ b/templates/expo-template-default/package.json @@ -29,7 +29,7 @@ "react": "19.2.3", "react-dom": "19.2.3", "react-native": "0.86.0-rc.3", - "react-native-gesture-handler": "~2.31.2", + "react-native-gesture-handler": "~2.32.0", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "~5.7.0", "react-native-screens": "4.25.2", diff --git a/tools/src/commands/SetupReactNativeNightly.ts b/tools/src/commands/SetupReactNativeNightly.ts index 96a9c4e09c0bab..998fb1dc6245d8 100644 --- a/tools/src/commands/SetupReactNativeNightly.ts +++ b/tools/src/commands/SetupReactNativeNightly.ts @@ -54,7 +54,6 @@ async function main() { const patches = [ 'datetimepicker.patch', 'lottie-react-native.patch', - 'react-native-gesture-handler.patch', 'react-native-pager-view.patch', 'react-native-screens.patch', 'react-native-reanimated.patch', diff --git a/tools/src/react-native-nightlies/patches/react-native-gesture-handler.patch b/tools/src/react-native-nightlies/patches/react-native-gesture-handler.patch deleted file mode 100644 index 2b01ed5f2f0d93..00000000000000 --- a/tools/src/react-native-nightlies/patches/react-native-gesture-handler.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/node_modules/react-native-gesture-handler/ios/RNGestureHandlerModule.mm -+++ b/node_modules/react-native-gesture-handler/ios/RNGestureHandlerModule.mm -@@ -96,7 +96,7 @@ - return jsi::Value::null(); - } - -- auto shadowNode = arguments[0].asObject(runtime).getHostObject(runtime)->shadowNode; -+ auto shadowNode = arguments[0].asObject(runtime).getNativeState(runtime); - bool isFormsStackingContext = shadowNode->getTraits().check(ShadowNodeTraits::FormsStackingContext); - - return jsi::Value(isFormsStackingContext);