diff --git a/.github/actions/detect-platform-change/action.yml b/.github/actions/detect-platform-change/action.yml index b85e8d2d35f67f..e81669762a0078 100644 --- a/.github/actions/detect-platform-change/action.yml +++ b/.github/actions/detect-platform-change/action.yml @@ -14,7 +14,7 @@ inputs: description: 'Paths to ignore for all platforms' required: false default: >- - "!{**/*.md,**/LICENSE*,**/.gitignore,**/CHANGELOG*,**/.npmignore,**/.eslintrc*,**/.prettierrc*,**/.gitattributes,**/.watchmanconfig,**/.fingerprintignore}" + "!{**/*.md,**/LICENSE*,**/.gitignore,**/CHANGELOG*,**/.npmignore,**/.eslintrc*,**/.prettierrc*,**/.gitattributes,**/.watchmanconfig,**/.fingerprintignore,**/*.web.*}" outputs: should_run_android: diff --git a/.github/workflows/brownfield.yml b/.github/workflows/brownfield.yml index c634fa90aee7f1..d4cb7a06e3988c 100644 --- a/.github/workflows/brownfield.yml +++ b/.github/workflows/brownfield.yml @@ -275,10 +275,6 @@ jobs: runs-on: macos-15 needs: analyze-changes if: needs.analyze-changes.outputs.compilation_test_ios == 'true' || needs.analyze-changes.outputs.all_tests == 'true' - strategy: - fail-fast: true - matrix: - build-type: [debug, release] steps: - name: ๐Ÿ‘€ Checkout uses: actions/checkout@v5 @@ -302,10 +298,13 @@ jobs: run: yarn install --frozen-lockfile - name: ๐Ÿ‘ท Build Expo CLI run: yarn workspace @expo/cli prepare - - name: ๐Ÿ Build iOS artifacts + - name: ๐Ÿ Build iOS artifacts (Release) run: | npx expo prebuild --clean --platform ios - npx expo-brownfield build:ios --${{ matrix.build-type }} --verbose + npx expo-brownfield build:ios --release --verbose + working-directory: apps/brownfield-tester/expo-app + - name: ๐Ÿ Build iOS artifacts (Debug) + run: npx expo-brownfield build:ios --debug --verbose working-directory: apps/brownfield-tester/expo-app - name: ๐Ÿ”” Notify on Slack uses: ./.github/actions/slack-notify diff --git a/.github/workflows/test-suite-brownfield-isolated.yml b/.github/workflows/test-suite-brownfield-isolated.yml index d1f175b7ccaa9c..6c99313a99d475 100644 --- a/.github/workflows/test-suite-brownfield-isolated.yml +++ b/.github/workflows/test-suite-brownfield-isolated.yml @@ -46,13 +46,10 @@ jobs: "packages/expo-brownfield/src/**", "packages/expo-brownfield/e2e/maestro/**" - android-e2e: + android-build: runs-on: ubuntu-24.04 needs: detect-platform-for-e2e if: needs.detect-platform-for-e2e.outputs.should_run_android == 'true' - strategy: - matrix: - api-level: [36] env: ORG_GRADLE_PROJECT_reactNativeArchitectures: x86_64 GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:MaxMetaspaceSize=4096m" @@ -84,11 +81,46 @@ jobs: react-native-gradle-downloads: 'true' - name: ๐Ÿงถ Install workspace node modules run: yarn install --frozen-lockfile + - name: ๐Ÿ‘ท Build Expo CLI + run: yarn workspace @expo/cli prepare - name: ๐Ÿค– Build and publish Android artifacts (apps/brownfield-tester/expo-app) run: | npx expo prebuild --clean -p android npx expo-brownfield build:android --repo MavenLocal --verbose working-directory: apps/brownfield-tester/expo-app + - name: ๐Ÿ—๏ธ Build APK + run: | + ./gradlew clean + ./gradlew assembleRelease --refresh-dependencies + working-directory: apps/brownfield-tester/android-integrated + - name: ๐Ÿ’พ Store APK artifact + uses: actions/upload-artifact@v4 + with: + name: expo-brownfield-android-release + path: apps/brownfield-tester/android-integrated/app/build/outputs/apk/release/app-release.apk + + android-e2e: + runs-on: ubuntu-24.04 + needs: android-build + strategy: + matrix: + api-level: [36] + steps: + - name: ๐Ÿ‘€ Checkout + uses: actions/checkout@v5 + - name: ๐Ÿงน Cleanup GitHub Linux runner disk space + uses: ./.github/actions/cleanup-linux-disk-space + - name: ๐Ÿ—๏ธ Setup Bun + uses: oven-sh/setup-bun@v2 + with: + # Version `1.x` fails due to https://github.com/oven-sh/setup-bun/issues/37 + # TODO(cedric): swap `latest` back once the issue is resolved + bun-version: latest + - name: ๐ŸŒ  Download builds + uses: actions/download-artifact@v4 + with: + name: expo-brownfield-android-release + path: apps/brownfield-tester/android-integrated/apk - name: ๐Ÿบ Install Maestro run: | curl -Ls "https://get.maestro.mobile.dev" | bash @@ -99,7 +131,7 @@ jobs: avd-api: ${{ matrix.api-level }} avd-name: avd-${{ matrix.api-level }} script: | - cd apps/brownfield-tester/android-integrated && ./gradlew clean && ./gradlew installRelease --refresh-dependencies + adb install -r apps/brownfield-tester/android-integrated/apk/*.apk cd packages/expo-brownfield/e2e && maestro test maestro/__tests__/android - name: ๐Ÿ”” Notify on Slack uses: ./.github/actions/slack-notify diff --git a/apps/expo-go/android/expoview/src/main/res/values/strings.xml b/apps/expo-go/android/expoview/src/main/res/values/strings.xml index a0dd88bd27da1f..216cbad7378c39 100644 --- a/apps/expo-go/android/expoview/src/main/res/values/strings.xml +++ b/apps/expo-go/android/expoview/src/main/res/values/strings.xml @@ -39,19 +39,6 @@ Expo Experience notifications Persistent notifications that provide debug info about open experiences - Hide Element Inspector - Show Element Inspector - Element Inspector Unavailable - Open JS Debugger - Disable Fast Refresh - Enable Fast Refresh - Show developer action button - Hide developer action button - Fast Refresh Unavailable - Use the Reload button above to reload when in production mode. Switch back to development mode to use Fast Refresh. - Hide Performance Monitor - Show Performance Monitor - Performance Monitor Unavailable contain false Make sure you are signed in to the same Expo account on your computer and this app. Also verify that your computer is connected to the internet, and ideally to the same Wi-Fi network as your mobile device. Lastly, ensure that you are using the latest version of Expo CLI. Pull to refresh to update. diff --git a/apps/expo-go/ios/Exponent/Versioned/Core/EXVersionManagerObjC.mm b/apps/expo-go/ios/Exponent/Versioned/Core/EXVersionManagerObjC.mm index cf68525e89e81e..90e4373dec4d53 100644 --- a/apps/expo-go/ios/Exponent/Versioned/Core/EXVersionManagerObjC.mm +++ b/apps/expo-go/ios/Exponent/Versioned/Core/EXVersionManagerObjC.mm @@ -167,7 +167,7 @@ - (RCTDevSettings *) devSettings:(id)host { } items[@"dev-remote-debug"] = @{ - @"label": @"Open JS Debugger", + @"label": @"Open DevTools", @"isEnabled": @YES }; diff --git a/apps/native-component-list/src/screens/Audio/AudioInputSelector.tsx b/apps/native-component-list/src/screens/Audio/AudioInputSelector.tsx index d1ed96de740b96..9746fc339f1884 100644 --- a/apps/native-component-list/src/screens/Audio/AudioInputSelector.tsx +++ b/apps/native-component-list/src/screens/Audio/AudioInputSelector.tsx @@ -6,9 +6,10 @@ import ListButton from '../../components/ListButton'; type Props = { recorder?: AudioRecorder; + canRecord?: boolean; }; -function AudioInputSelector({ recorder }: Props) { +function AudioInputSelector({ recorder, canRecord }: Props) { const [availableInputs, setAvailableInputs] = useState([]); const [currentInput, setCurrentInput] = useState(null); @@ -23,7 +24,7 @@ function AudioInputSelector({ recorder }: Props) { useEffect(() => { checkInputs(); - }, [checkInputs]); + }, [checkInputs, canRecord]); return ( diff --git a/apps/native-component-list/src/screens/Audio/AudioPlayer.tsx b/apps/native-component-list/src/screens/Audio/AudioPlayer.tsx index 418c6b5e017e61..664514d9d33c85 100644 --- a/apps/native-component-list/src/screens/Audio/AudioPlayer.tsx +++ b/apps/native-component-list/src/screens/Audio/AudioPlayer.tsx @@ -9,15 +9,21 @@ type AudioPlayerProps = { source: AudioSource | string | number; style?: StyleProp; downloadFirst?: boolean; + crossOrigin?: 'anonymous' | 'use-credentials'; }; const localSource = require('../../../assets/sounds/polonez.mp3'); const remoteSource = 'https://p.scdn.co/mp3-preview/f7a8ab9c5768009b65a30e9162555e8f21046f46?cid=162b7dc01f3a4a2ca32ed3cec83d1e02'; -export default function AudioPlayer({ source, style, downloadFirst = false }: AudioPlayerProps) { +export default function AudioPlayer({ + source, + style, + downloadFirst = false, + crossOrigin, +}: AudioPlayerProps) { const [currentSource, setCurrentSource] = React.useState(source); - const player = useAudioPlayer(source, { downloadFirst }); + const player = useAudioPlayer(source, { downloadFirst, crossOrigin }); const status = useAudioPlayerStatus(player); const setVolume = (volume: number) => { diff --git a/apps/native-component-list/src/screens/Audio/AudioPlayerScreen.tsx b/apps/native-component-list/src/screens/Audio/AudioPlayerScreen.tsx index 3ec530a109477c..2e0fec7cd3e62d 100644 --- a/apps/native-component-list/src/screens/Audio/AudioPlayerScreen.tsx +++ b/apps/native-component-list/src/screens/Audio/AudioPlayerScreen.tsx @@ -30,6 +30,7 @@ export default function AudioScreen(props: any) { Auth: 'Bearer some-token', }, }} + crossOrigin="anonymous" style={styles.player} /> Local asset player diff --git a/apps/native-component-list/src/screens/Audio/JsiAudioBar.tsx b/apps/native-component-list/src/screens/Audio/JsiAudioBar.tsx index a180b6ff0a67a4..12ac970d23f9d8 100644 --- a/apps/native-component-list/src/screens/Audio/JsiAudioBar.tsx +++ b/apps/native-component-list/src/screens/Audio/JsiAudioBar.tsx @@ -42,7 +42,11 @@ export function JsiAudioBar({ player, isPlaying }: { player: AudioPlayer; isPlay }); if (!player.isAudioSamplingSupported) { - return Audio sampling is not supported on this platform; + return ( + + Audio sampling requires the crossOrigin option for cross-origin sources + + ); } if (!isPlaying) { diff --git a/apps/native-component-list/src/screens/Audio/Recorder.tsx b/apps/native-component-list/src/screens/Audio/Recorder.tsx index 9c21faedc6d3c9..6a3199cd56f7d7 100644 --- a/apps/native-component-list/src/screens/Audio/Recorder.tsx +++ b/apps/native-component-list/src/screens/Audio/Recorder.tsx @@ -233,7 +233,7 @@ export default function Recorder({ onDone, style }: RecorderProps) { {_formatTime(recorderState.durationMillis / 1000)} - + {maybeRenderErrorOverlay()} ); diff --git a/docs/pages/debugging/tools.mdx b/docs/pages/debugging/tools.mdx index f5d90b3be166c5..4b031ac72dfd8f 100644 --- a/docs/pages/debugging/tools.mdx +++ b/docs/pages/debugging/tools.mdx @@ -45,7 +45,7 @@ The Developer menu provides the following options: - **Go Home**: To leave your app and navigate back to the dev client's or Expo Go app's Home screen. - **Toggle performance monitor**: To view the performance information about your app. - **Toggle element inspector**: To enable or disable the element inspector overlay. -- **Open JS debugger**: To open React Native DevTools which provides access to Console, Sources, Network (**Expo only**), Memory, Components, and Profiler, tabs for apps using Hermes. For more information, see the [Debugging with React Native DevTools](#debugging-with-react-native-devtools) section. +- **Open DevTools** (formerly **Open JS debugger**): To open React Native DevTools which provides access to Console, Sources, Network (**Expo only**), Memory, Components, and Profiler, tabs for apps using Hermes. For more information, see the [Debugging with React Native DevTools](#debugging-with-react-native-devtools) section. - **Fast Refresh**: To toggle automatic refreshing of the JS bundle whenever you make changes to files in your project using a text editor. Now, let's explore some of these options in details. diff --git a/docs/pages/guides/using-hermes.mdx b/docs/pages/guides/using-hermes.mdx index db8cd44a78eddc..55c2f60442ea25 100644 --- a/docs/pages/guides/using-hermes.mdx +++ b/docs/pages/guides/using-hermes.mdx @@ -36,7 +36,7 @@ Note that the Hermes bytecode format may change between different Hermes version ## JavaScript debugger -To debug JavaScript code running with Hermes, you can start your project with `npx expo start` then press j to open the debugger in Google Chrome or Microsoft Edge. The developer menu of development builds and Expo Go also have the **Open JS Debugger** option to do the same. +To debug JavaScript code running with Hermes, you can start your project with `npx expo start` then press j to open the debugger in Google Chrome or Microsoft Edge. The developer menu of development builds and Expo Go also have the **Open DevTools** (formerly **Open JS Debugger**) option to do the same. Alternatively, you can use the JavaScript inspector by opening [Google Chrome DevTools manually](https://reactnative.dev/docs/other-debugging-methods#remote-javascript-debugging-deprecated) diff --git a/docs/scripts/generate-markdown-pages-utils.test.ts b/docs/scripts/generate-markdown-pages-utils.test.ts index aae798b60a4b10..31a2201e8e3e8f 100644 --- a/docs/scripts/generate-markdown-pages-utils.test.ts +++ b/docs/scripts/generate-markdown-pages-utils.test.ts @@ -1352,7 +1352,6 @@ describe('extractFrontmatter', () => { path.join(tmpDir, 'full.mdx'), [ '---', - 'modificationDate: July 08, 2025', 'title: Camera', 'description: A camera component.', "platforms: ['android', 'ios']", @@ -1385,13 +1384,12 @@ describe('extractFrontmatter', () => { fs.rmSync(tmpDir, { recursive: true, force: true }); }); - it('extracts only modificationDate including delimiters', () => { + it('extracts full frontmatter including delimiters', () => { const result = extractFrontmatter(path.join(tmpDir, 'full.mdx')); expect(result).not.toBeNull(); - expect(result).toContain('modificationDate: July 08, 2025'); - expect(result).not.toContain('title: Camera'); - expect(result).not.toContain('description: A camera component.'); - expect(result).not.toContain('platforms:'); + expect(result).toContain('title: Camera'); + expect(result).toContain('description: A camera component.'); + expect(result).toContain('platforms:'); // Should include --- delimiters expect(result).toMatch(/^---\n/); expect(result).toMatch(/\n---\n$/); @@ -1399,14 +1397,19 @@ describe('extractFrontmatter', () => { expect(result).not.toContain('import'); }); - it('returns null when frontmatter has no modificationDate', () => { + it('extracts minimal frontmatter', () => { const result = extractFrontmatter(path.join(tmpDir, 'minimal.mdx')); - expect(result).toBeNull(); + expect(result).not.toBeNull(); + expect(result).toContain('title: Minimal'); + expect(result).not.toContain('# Minimal'); }); - it('returns null when modificationDate is empty', () => { + it('strips lines with empty values', () => { const result = extractFrontmatter(path.join(tmpDir, 'empty-values.mdx')); - expect(result).toBeNull(); + expect(result).not.toBeNull(); + expect(result).toContain('title: Camera'); + expect(result).toContain('description: A camera.'); + expect(result).not.toContain('modificationDate'); }); it('returns null when all frontmatter fields are empty', () => { diff --git a/docs/scripts/generate-markdown-pages-utils.ts b/docs/scripts/generate-markdown-pages-utils.ts index e3e546cfb2c526..0f7527a0aba89b 100644 --- a/docs/scripts/generate-markdown-pages-utils.ts +++ b/docs/scripts/generate-markdown-pages-utils.ts @@ -25,7 +25,8 @@ export function findMdxSource(htmlPath: string, outDir: string, pagesDir: string /** * Extract the raw YAML frontmatter block (including --- delimiters) from an MDX file. - * Keeps only non-empty `modificationDate` and drops other frontmatter fields. + * Strips lines with empty values (e.g. `modificationDate:` injected by append-dates.js + * with no value in shallow CI clones). * Returns the frontmatter string with trailing newline, or null if no frontmatter found. */ export function extractFrontmatter(mdxPath: string): string | null { @@ -36,12 +37,12 @@ export function extractFrontmatter(mdxPath: string): string | null { } const filtered = match[1] .split('\n') - .filter(line => /^modificationDate:\s+\S/.test(line)) + .filter(line => !/^\w+:\s*$/.test(line)) .join('\n'); if (!filtered.trim()) { return null; } - return '---\n' + filtered + '\n---\n'; + return '---\n' + filtered + '---\n'; } function createTurndownService(): TurndownService { diff --git a/guides/releasing/Quality Assurance.md b/guides/releasing/Quality Assurance.md index b69b7f0d974274..7214654d638b62 100644 --- a/guides/releasing/Quality Assurance.md +++ b/guides/releasing/Quality Assurance.md @@ -20,7 +20,7 @@ Unversioned QA: Test in native-component-list. - Reload manually, your change should appear - Make and save another change, reenable Fast Refresh, your change should show up automatically - Debug JS in-place - - Open JS debugger either pressing `j` or from the dev menu in Expo Go + - Open DevTools either pressing `j` or from the dev menu in Expo Go - Add a breakpoint (maybe add a button to your app), ensure the breakpoint works - Click Reload on the webpage, make sure it reloads the app - Other dev tools diff --git a/packages/@expo/cli/e2e/__tests__/export/server.test.ts b/packages/@expo/cli/e2e/__tests__/export/server.test.ts index 6c89abf592662e..e00466b6dbe8ec 100644 --- a/packages/@expo/cli/e2e/__tests__/export/server.test.ts +++ b/packages/@expo/cli/e2e/__tests__/export/server.test.ts @@ -245,7 +245,7 @@ describe('server-output', () => { (server.isWorkerd ? it.skip : it)('supports runtime API', async () => { await expect(server.fetchAsync('/api/runtime').then((r) => r.json())).resolves.toEqual({ environment: expect.stringMatching(/production|development/), - origin: 'null', + origin: expect.stringMatching(/^http/), }); }); diff --git a/packages/expo-audio/CHANGELOG.md b/packages/expo-audio/CHANGELOG.md index 53cc410f7e549c..4dea42b08ae661 100644 --- a/packages/expo-audio/CHANGELOG.md +++ b/packages/expo-audio/CHANGELOG.md @@ -8,6 +8,10 @@ - [iOS] Add support for `shouldRouteThroughEarpiece`. ([#43089](https://github.com/expo/expo/pull/43089) by [@alanjhughes](https://github.com/alanjhughes)) - [Android] Make it possible to add/remove the foreground service and foreground service permissions with a config plugin. ([#43014](https://github.com/expo/expo/pull/43014) by [@behenate](https://github.com/behenate)) +- [Web] Add support for audio sampling. ([#43149](https://github.com/expo/expo/pull/43149) by [@alanjhughes](https://github.com/alanjhughes)) +- [Web] Add support for media controls. ([#43150](https://github.com/expo/expo/pull/43150) by [@alanjhughes](https://github.com/alanjhughes)) +- [Web] Add support for selecting recording inputs. ([#43151](https://github.com/expo/expo/pull/43151) by [@alanjhughes](https://github.com/alanjhughes)) +- [Web] Add support for recording metering. ([#43152](https://github.com/expo/expo/pull/43152) by [@alanjhughes](https://github.com/alanjhughes)) ### ๐Ÿ› Bug fixes @@ -17,6 +21,7 @@ ### ๐Ÿ’ก Others - [Android] Improve event handling. ([#43121](https://github.com/expo/expo/pull/43121) by [@alanjhughes](https://github.com/alanjhughes)) +- [Android] Rework native audio service handling. ([#43015](https://github.com/expo/expo/pull/43015) by [@behenate](https://github.com/behenate)) ## 55.0.5 โ€” 2026-02-08 diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioExceptions.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioExceptions.kt index 0fdaa052ff9e60..ccb347222793d8 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioExceptions.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioExceptions.kt @@ -2,9 +2,24 @@ package expo.modules.audio import expo.modules.kotlin.exception.CodedException +private const val defaultPlaybackServiceTip = + "Make sure that the expo-audio config plugin is properly configured with " + + "'enableBackgroundPlayback: true' to avoid issues with lock screen controls " + + "and background audio playback." + +private const val defaultRecordingServiceTip = + "Make sure that the expo-audio config plugin is properly configured with " + + "'enableBackgroundRecording: true' to avoid issues with background recording." + internal class AudioPermissionsException : CodedException("RECORD_AUDIO permission has not been granted") +internal class NotificationPermissionsException : + CodedException( + "POST_NOTIFICATIONS permission has not been granted. This permission is required when using background recording (allowsBackgroundRecording: true). " + + "Request notification permissions using AudioModule.requestNotificationPermissionsAsync() before calling prepareRecording()." + ) + internal class GetAudioInputNotSupportedException : CodedException("Getting current audio input is not supported on devices running Android version lower than Android 9.0") @@ -22,3 +37,23 @@ internal class AudioRecorderPrepareException(cause: Throwable) : internal class AudioRecorderAlreadyPreparedException : CodedException("AudioRecorder has already been prepared. Stop or release the current session before preparing again.") + +internal fun getPlaybackServiceErrorMessage( + message: String?, + tip: String = defaultPlaybackServiceTip +): String { + return (message ?: "expo-audio playback service error") + ". $tip" +} + +internal fun getRecordingServiceErrorMessage( + message: String?, + tip: String = defaultRecordingServiceTip +): String { + return (message ?: "expo-audio recording service error") + ". $tip" +} + +internal class AudioRecordingServiceException(message: String?, cause: Throwable? = null) : + CodedException(getRecordingServiceErrorMessage(message), cause) + +internal class AudioPlaybackServiceException(message: String?, cause: Throwable? = null) : + CodedException(getPlaybackServiceErrorMessage(message), cause) diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioModule.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioModule.kt index 9b0214af6ecf08..722063aee9df84 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioModule.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioModule.kt @@ -28,10 +28,10 @@ import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.smoothstreaming.SsMediaSource import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.ProgressiveMediaSource -import expo.modules.audio.service.AudioControlsService import expo.modules.interfaces.permissions.Permissions import expo.modules.kotlin.Promise import expo.modules.kotlin.exception.Exceptions +import expo.modules.kotlin.functions.Coroutine import expo.modules.kotlin.functions.Queues import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition @@ -273,8 +273,6 @@ class AudioModule : Module() { recorders.values.forEach { it.stopRecording() } - - AudioControlsService.clearSession() } } @@ -498,7 +496,7 @@ class AudioModule : Module() { recorder.getCurrentTimeSeconds() } - AsyncFunction("prepareToRecordAsync") { recorder: AudioRecorder, options: RecordingOptions? -> + AsyncFunction("prepareToRecordAsync") Coroutine { recorder: AudioRecorder, options: RecordingOptions? -> checkRecordingPermission() recorder.prepareRecording(options) } diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioPlayer.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioPlayer.kt index a9ccec7164e1ad..38a1d95bbbebf6 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioPlayer.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioPlayer.kt @@ -13,7 +13,9 @@ import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.source.MediaSource -import expo.modules.audio.service.AudioControlsService +import androidx.media3.session.MediaSession +import expo.modules.audio.service.AudioPlaybackServiceConnection +import expo.modules.audio.service.ServiceBindingState import expo.modules.kotlin.AppContext import expo.modules.kotlin.exception.Exceptions import expo.modules.kotlin.sharedobjects.SharedRef @@ -29,7 +31,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch - +import java.lang.ref.WeakReference import java.util.UUID private const val PLAYBACK_STATUS_UPDATE = "playbackStatusUpdate" @@ -60,7 +62,10 @@ class AudioPlayer( // Lock screen controls var isActiveForLockScreen = false - private var metadata: Metadata? = null + internal var metadata: Metadata? = null + internal var lockScreenOptions: AudioLockScreenOptions? = null + internal var mediaSession: MediaSession = buildBasicMediaSession(context, ref) + val serviceConnection = AudioPlaybackServiceConnection(WeakReference(this), appContext) private var playerScope = CoroutineScope(Dispatchers.Main) private var samplingEnabled = false @@ -108,22 +113,47 @@ class AudioPlayer( fun setActiveForLockScreen(active: Boolean, metadata: Metadata? = null, options: AudioLockScreenOptions? = null) { if (active) { this.metadata = metadata - AudioControlsService.setActivePlayer(context, this, metadata, options) + this.lockScreenOptions = options + this.isActiveForLockScreen = true + + if (serviceConnection.bindingState == ServiceBindingState.UNBOUND) { + serviceConnection.bindWithService() + } + + val serviceBinder = serviceConnection.playbackServiceBinder + if (serviceBinder != null && serviceConnection.bindingState == ServiceBindingState.BOUND) { + serviceBinder.service.setPlayerOptions(this, metadata, options) + } else if (serviceConnection.bindingState == ServiceBindingState.BINDING) { + // The settings will be applied when the service connects + } else { + appContext?.jsLogger?.error( + getPlaybackServiceErrorMessage("Failed to activate lock screen controls - service binding failed") + ) + } } else if (isActiveForLockScreen) { - AudioControlsService.setActivePlayer(context, null) + this.isActiveForLockScreen = false + serviceConnection.playbackServiceBinder?.service?.unregisterPlayer() } } fun updateLockScreenMetadata(metadata: Metadata) { if (isActiveForLockScreen) { this.metadata = metadata - AudioControlsService.updateMetadata(this, metadata) + + val serviceBinder = serviceConnection.playbackServiceBinder + if (serviceBinder != null && serviceConnection.bindingState == ServiceBindingState.BOUND) { + serviceBinder.service.setPlayerMetadata(this, metadata) + } else { + appContext?.jsLogger?.warn( + getPlaybackServiceErrorMessage("Cannot update lock screen metadata - service not connected") + ) + } } } fun clearLockScreenControls() { if (isActiveForLockScreen) { - AudioControlsService.setActivePlayer(context, null) + serviceConnection.playbackServiceBinder?.service?.unregisterPlayer() } } @@ -252,6 +282,11 @@ class AudioPlayer( ) } + internal fun assignBasicMediaSession() { + mediaSession.release() + mediaSession = buildBasicMediaSession(context, ref) + } + private fun sendPlayerUpdate(map: Map? = null) { val data = currentStatus() val body = map?.let { data + it } ?: data @@ -308,12 +343,17 @@ class AudioPlayer( @OptIn(DelicateCoroutinesApi::class) override fun sharedObjectDidRelease() { super.sharedObjectDidRelease() + + serviceConnection.release() + // Run on global scope (not appContext.mainQueue) so that reloading doesn't cancel the release process // https://github.com/expo/expo/blob/cdf592a7fea56fc01b0149e9b2e5dbd294bcdc4c/packages/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt#L277-L279 GlobalScope.launch(Dispatchers.Main) { + mediaSession.release() if (isActiveForLockScreen) { - AudioControlsService.clearSession() + serviceConnection.playbackServiceBinder?.service?.unregisterPlayer() } + serviceConnection.unbind() playerScope.cancel() visualizer?.release() ref.release() diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioRecorder.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioRecorder.kt index 1483b76fc6fba1..77529633e372a6 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioRecorder.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioRecorder.kt @@ -13,15 +13,19 @@ import android.os.Build import android.os.Bundle import androidx.core.content.ContextCompat import androidx.core.net.toUri -import expo.modules.audio.service.AudioRecordingService +import expo.modules.audio.service.AudioRecordingServiceConnection import expo.modules.kotlin.AppContext +import expo.modules.kotlin.exception.CodedException +import expo.modules.kotlin.exception.Exceptions import expo.modules.kotlin.sharedobjects.SharedObject import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch import java.io.File import java.io.IOException +import java.lang.ref.WeakReference import java.util.UUID +import kotlin.coroutines.Continuation import kotlin.math.log10 private const val RECORDING_STATUS_UPDATE = "recordingStatusUpdate" @@ -45,7 +49,14 @@ class AudioRecorder( var isPaused = false private var recordingTimerJob: Job? = null var useForegroundService = false - private var isRegisteredWithService = false + private var bindingContinuation: Continuation? = null + + val serviceConnection = AudioRecordingServiceConnection(WeakReference(this), appContext) + + private val _appContext: AppContext + get() { + return appContext ?: throw Exceptions.AppContextLost() + } private fun currentFileUrl(): String? = filePath?.let(::File)?.toUri()?.toString() @@ -71,25 +82,41 @@ class AudioRecorder( } } - fun prepareRecording(options: RecordingOptions?) { + suspend fun prepareRecording(options: RecordingOptions?) { if (recorder != null || isPrepared || isRecording || isPaused) { throw AudioRecorderAlreadyPreparedException() } + + if (useForegroundService && !hasNotificationPermissions()) { + throw NotificationPermissionsException() + } + val recordingOptions = options ?: this.options val mediaRecorder = createRecorder(recordingOptions) recorder = mediaRecorder + try { + if (useForegroundService) { + serviceConnection.bindWithService() + } mediaRecorder.prepare() isPrepared = true - } catch (cause: Exception) { + } catch (e: Exception) { mediaRecorder.release() recorder = null isPrepared = false - throw AudioRecorderPrepareException(cause) + + throw e as? CodedException ?: AudioRecorderPrepareException(e) } } fun record() { + if (useForegroundService) { + serviceConnection.recordingServiceBinder?.service?.registerRecorder(this) ?: run { + throw AudioRecordingServiceException("The service connection is not bound, but `allowsBackgroundRecording` is set to `true`") + } + } + if (isPaused) { recorder?.resume() } else { @@ -98,11 +125,6 @@ class AudioRecorder( startTime = System.currentTimeMillis() isRecording = true isPaused = false - - if (useForegroundService && !isRegisteredWithService) { - AudioRecordingService.startService(context, this) - isRegisteredWithService = true - } } fun recordWithOptions(atTimeSeconds: Double? = null, forDurationSeconds: Double? = null) { @@ -147,9 +169,8 @@ class AudioRecorder( var stopFailed = false var stopError: String? = null - if (useForegroundService && isRegisteredWithService) { - AudioRecordingService.getInstance()?.unregisterRecorder(this) - isRegisteredWithService = false + if (useForegroundService) { + serviceConnection.recordingServiceBinder?.service?.unregisterRecorder(this) } try { @@ -259,9 +280,16 @@ class AudioRecorder( override fun sharedObjectDidRelease() { super.sharedObjectDidRelease() - if (useForegroundService && isRegisteredWithService) { - AudioRecordingService.getInstance()?.unregisterRecorder(this) - isRegisteredWithService = false + + // Mark recorder as released + serviceConnection.release() + + if (useForegroundService) { + serviceConnection.recordingServiceBinder?.service?.unregisterRecorder(this) + // Unbind service connection + serviceConnection.unbind() + // Clean up service connection resources + serviceConnection.cleanup() } reset() } @@ -319,9 +347,10 @@ class AudioRecorder( MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED -> { val url = currentFileUrl() - if (useForegroundService && isRegisteredWithService) { - AudioRecordingService.getInstance()?.unregisterRecorder(this) - isRegisteredWithService = false + if (useForegroundService) { + serviceConnection.recordingServiceBinder?.service?.unregisterRecorder(this) + // Unbind the service connection + serviceConnection.unbind() } try { @@ -390,6 +419,14 @@ class AudioRecorder( private fun hasRecordingPermissions() = ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED + private fun hasNotificationPermissions(): Boolean { + // POST_NOTIFICATIONS permission is only required on Android 13+ (API 33+) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + return true + } + return ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED + } + fun getAvailableInputs(audioManager: AudioManager) = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS).mapNotNull { deviceInfo -> val type = deviceInfo.type diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioUtils.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioUtils.kt index 267f27f2837514..dca91c32a2787a 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioUtils.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/AudioUtils.kt @@ -1,7 +1,10 @@ package expo.modules.audio +import android.content.Context import android.media.AudioDeviceInfo import android.os.Bundle +import androidx.media3.exoplayer.ExoPlayer +import androidx.media3.session.MediaSession import java.io.File import java.io.IOException @@ -27,3 +30,9 @@ fun getMapFromDeviceInfo(deviceInfo: AudioDeviceInfo): Bundle { map.putString("uid", deviceInfo.id.toString()) return map } + +fun buildBasicMediaSession(context: Context, player: ExoPlayer): MediaSession { + return MediaSession.Builder(context, player) + .setId("ExpoAudioBasicMediaSession_${player.hashCode()}") + .build() +} diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioControlsService.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioControlsService.kt index 04486e21da2f96..1d9eea1a8a312a 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioControlsService.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioControlsService.kt @@ -9,12 +9,9 @@ import android.content.Intent import android.content.pm.ServiceInfo import android.graphics.Bitmap import android.graphics.BitmapFactory -import android.os.Binder import android.os.Build import android.os.Bundle -import android.os.Handler import android.os.IBinder -import android.os.Looper import androidx.annotation.OptIn import androidx.core.app.NotificationCompat import androidx.media3.common.Player @@ -27,15 +24,20 @@ import androidx.media3.session.SessionCommand import expo.modules.audio.AudioLockScreenOptions import expo.modules.audio.AudioPlayer import expo.modules.audio.Metadata +import expo.modules.audio.getPlaybackServiceErrorMessage +import expo.modules.kotlin.AppContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.cancel +import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import java.lang.ref.WeakReference import java.net.URL @OptIn(UnstableApi::class) class AudioControlsService : MediaSessionService() { - private val binder = AudioControlsBinder() + private val binder = AudioPlaybackServiceBinder(this) private var mediaSession: MediaSession? = null private var currentMetadata: Metadata? = null private var currentPlayer: AudioPlayer? = null @@ -43,48 +45,46 @@ class AudioControlsService : MediaSessionService() { private val scope = CoroutineScope(Dispatchers.IO) private var currentArtworkUrl: URL? = null private var currentArtwork: Bitmap? = null + private var artworkLoadJob: Job? = null private val notificationId: Int get() = currentPlayer?.hashCode() ?: CHANNEL_ID.hashCode() - private var playbackListener: Player.Listener? = null + private var weakContext: WeakReference? = null + var appContext: AppContext? + get() = weakContext?.get() + set(value) { + weakContext = value?.let { WeakReference(it) } + } - inner class AudioControlsBinder : Binder() { - fun getService(): AudioControlsService = this@AudioControlsService - } + var playbackListener: Player.Listener? = null override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - // Handle media button actions dispatched from notification - when (intent?.action) { - ACTION_PLAY -> withPlayerOnAppThread { it.play() } - ACTION_PAUSE -> withPlayerOnAppThread { it.pause() } - ACTION_TOGGLE -> withPlayerOnAppThread { player -> - if (player.isPlaying) player.pause() else player.play() - } - - ACTION_SEEK_FORWARD -> withPlayerOnAppThread { player -> - player.seekTo(player.currentPosition + SEEK_INTERVAL_MS) - } - - ACTION_SEEK_BACKWARD -> withPlayerOnAppThread { player -> - player.seekTo(player.currentPosition - SEEK_INTERVAL_MS) + val currentPlayerRef = currentPlayer?.ref ?: return super.onStartCommand(intent, flags, startId) + val context = appContext ?: return super.onStartCommand(intent, flags, startId) + + context.mainQueue.launch { + when (intent?.action) { + ACTION_PLAY -> currentPlayerRef.play() + ACTION_PAUSE -> currentPlayerRef.pause() + ACTION_TOGGLE -> + if (currentPlayerRef.isPlaying) { + currentPlayerRef.pause() + } else { + currentPlayerRef.play() + } + + ACTION_SEEK_FORWARD -> currentPlayerRef.seekTo(currentPlayerRef.currentPosition + SEEK_INTERVAL_MS) + ACTION_SEEK_BACKWARD -> currentPlayerRef.seekTo(currentPlayerRef.currentPosition - SEEK_INTERVAL_MS) } } - // Ensure channel exists and update current notification postOrStartForegroundNotification(startInForeground = false) return super.onStartCommand(intent, flags, startId) } override fun onCreate() { super.onCreate() - instance = this createNotificationChannelIfNeeded() - - pendingPlayer?.let { player -> - setActivePlayerInternal(player, pendingMetadata, pendingOptions) - pendingPlayer = null - pendingMetadata = null - } } private fun createNotificationChannelIfNeeded() { @@ -117,6 +117,7 @@ class AudioControlsService : MediaSessionService() { val builder = NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(androidx.media3.session.R.drawable.media3_icon_circular_play) + // If the title is null or empty string android sets the notification to " is running..." we want to keep the notification empty so we \u200E to keep the text empty. .setContentTitle(currentMetadata?.title ?: "\u200E") .setContentText(currentMetadata?.artist) .setSubText(currentMetadata?.albumTitle) @@ -175,14 +176,21 @@ class AudioControlsService : MediaSessionService() { val notification = buildNotification() ?: return if (startInForeground) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - startForeground( - notificationId, - notification, - ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + startForeground( + notificationId, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK + ) + } else { + startForeground(notificationId, notification) + } + } catch (e: Exception) { + appContext?.jsLogger?.error( + getPlaybackServiceErrorMessage("Failed to start the expo-audio foreground service for lock screen controls"), + e ) - } else { - startForeground(notificationId, notification) } } else { notificationManager.notify(notificationId, notification) @@ -190,7 +198,6 @@ class AudioControlsService : MediaSessionService() { } override fun onUpdateNotification(session: MediaSession, startInForegroundRequired: Boolean) { - // Called by Media3 when the session's notification should be updated. postOrStartForegroundNotification(startInForegroundRequired) } @@ -199,10 +206,11 @@ class AudioControlsService : MediaSessionService() { metadata: Metadata? = null, options: AudioLockScreenOptions? = null ) { - // Detach listener from previous player, clear active flag and hide - playbackListener?.let { listener -> - currentPlayer?.ref?.removeListener(listener) + appContext?.mainQueue?.launch { + val playbackListener = playbackListener ?: return@launch + currentPlayer?.ref?.removeListener(playbackListener) } + playbackListener = null currentPlayer?.isActiveForLockScreen = false hideNotification() @@ -222,33 +230,28 @@ class AudioControlsService : MediaSessionService() { if (player != null) { mediaSession?.release() - val session = MediaSession.Builder(this, player.ref) - .setCallback(AudioMediaSessionCallback()) - .build() + appContext?.mainQueue?.launch { + val context = appContext?.reactContext ?: return@launch + val session = MediaSession.Builder(context, player.ref) + .setCallback(AudioMediaSessionCallback()) + .build() - addSession(session) - mediaSession = session + // Replace the basic media session with a session connected to our playback service. + player.mediaSession.release() + player.mediaSession = session - // Set initial custom layout - updateSessionCustomLayout(player.ref.isPlaying) + addSession(session) + mediaSession = session - postOrStartForegroundNotification(startInForeground = true) + updateSessionCustomLayout(player.ref.isPlaying) - // Listen for playback state changes to refresh notification and update custom layout - val listener = object : Player.Listener { - override fun onIsPlayingChanged(isPlaying: Boolean) { - updateSessionCustomLayout(isPlaying) - postOrStartForegroundNotification(startInForeground = false) - } + postOrStartForegroundNotification(startInForeground = true) - override fun onPlaybackStateChanged(playbackState: Int) { - postOrStartForegroundNotification(startInForeground = false) - } + addPlayerListener(player) + + // Initial update now that session exists + postOrStartForegroundNotification(startInForeground = false) } - playbackListener = listener - player.ref.addListener(listener) - // Initial update now that session exists - postOrStartForegroundNotification(startInForeground = false) } else { clearSessionInternal() } @@ -269,14 +272,12 @@ class AudioControlsService : MediaSessionService() { private fun clearSessionInternal() { currentPlayer?.isActiveForLockScreen = false - playbackListener?.let { listener -> - currentPlayer?.ref?.removeListener(listener) - } - playbackListener = null + removePlayerListener() currentPlayer = null currentMetadata = null mediaSession?.release() mediaSession = null + currentPlayer?.assignBasicMediaSession() stopForeground(STOP_FOREGROUND_REMOVE) } @@ -284,30 +285,64 @@ class AudioControlsService : MediaSessionService() { return mediaSession } - private fun withPlayerOnAppThread(block: (Player) -> Unit) { - val player = currentPlayer?.ref ?: return - val looper: Looper = player.applicationLooper - if (Looper.myLooper() == looper) { - block(player) + override fun onBind(intent: Intent?): IBinder { + super.onBind(intent) + return binder + } + + fun registerPlayer(player: AudioPlayer) { + setActivePlayerInternal(player, null, null) + } + + fun setPlayerMetadata(player: AudioPlayer, metadata: Metadata?) { + updateMetadataInternal(player, metadata) + } + + fun setPlayerOptions( + player: AudioPlayer, + metadata: Metadata?, + options: AudioLockScreenOptions? + ) { + if (player == currentPlayer) { + currentMetadata = metadata + currentOptions = options + + // Reload artwork if metadata has changed + metadata?.artworkUrl?.let { + loadArtworkFromUrl(it) { bitmap -> + currentArtwork = bitmap + postOrStartForegroundNotification(startInForeground = false) + } + } + + updateSessionCustomLayout(player.ref.isPlaying) + postOrStartForegroundNotification(startInForeground = false) } else { - Handler(looper).post { block(player) } + setActivePlayerInternal(player, metadata, options) } } - override fun onBind(intent: Intent?): IBinder { - return super.onBind(intent) ?: binder + fun unregisterPlayer() { + clearSessionInternal() } private fun loadArtworkFromUrl(url: URL, callback: (Bitmap?) -> Unit) { if (url != currentArtworkUrl) { currentArtworkUrl = url - scope.launch { + artworkLoadJob?.cancel() + + artworkLoadJob = scope.launch { try { val inputStream = url.openConnection().getInputStream() val bitmap = BitmapFactory.decodeStream(inputStream) - callback(bitmap) + + if (isActive) { + callback(bitmap) + } } catch (e: Exception) { - callback(null) + if (isActive) { + callback(null) + } } } } @@ -321,14 +356,41 @@ class AudioControlsService : MediaSessionService() { override fun onDestroy() { super.onDestroy() - instance = null - try { - scope.cancel() - } catch (e: Exception) { - // - } + + artworkLoadJob?.cancel() + artworkLoadJob = null + scope.cancel() mediaSession?.release() + mediaSession = null currentPlayer = null + currentMetadata = null + currentOptions = null + currentArtwork = null + currentArtworkUrl = null + removePlayerListener() + } + + private fun addPlayerListener(player: AudioPlayer) { + val listener = object : Player.Listener { + override fun onIsPlayingChanged(isPlaying: Boolean) { + updateSessionCustomLayout(isPlaying) + postOrStartForegroundNotification(startInForeground = false) + } + + override fun onPlaybackStateChanged(playbackState: Int) { + postOrStartForegroundNotification(startInForeground = false) + } + } + playbackListener = listener + player.ref.addListener(listener) + } + + private fun removePlayerListener() { + appContext?.mainQueue?.launch { + val listener = playbackListener ?: return@launch + currentPlayer?.ref?.removeListener(listener) + playbackListener = null + } } companion object { @@ -338,48 +400,8 @@ class AudioControlsService : MediaSessionService() { private const val ACTION_TOGGLE = "expo.modules.audio.action.TOGGLE" const val ACTION_SEEK_FORWARD = "expo.modules.audio.action.SEEK_FORWARD" - const val ACTION_SEEK_BACKWARD = "expo.modules.audio.action.SEEK_REWIND" + const val ACTION_SEEK_BACKWARD = "expo.modules.audio.action.SEEK_BACKWARD" const val SEEK_INTERVAL_MS = 10000L - - private var pendingPlayer: AudioPlayer? = null - private var pendingMetadata: Metadata? = null - private var pendingOptions: AudioLockScreenOptions? = null - - @Volatile - private var instance: AudioControlsService? = null - - fun getInstance(): AudioControlsService? = instance - - fun setActivePlayer( - context: Context, - player: AudioPlayer?, - metadata: Metadata? = null, - options: AudioLockScreenOptions? = null - ) { - val service = getInstance() - if (service != null) { - service.setActivePlayerInternal(player, metadata, options) - } else { - val intent = Intent(context, AudioControlsService::class.java) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } - - pendingPlayer = player - pendingMetadata = metadata - pendingOptions = options - } - } - - fun updateMetadata(player: AudioPlayer, metadata: Metadata?) { - getInstance()?.updateMetadataInternal(player, metadata) - } - - fun clearSession() { - getInstance()?.clearSessionInternal() - } } } diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioPlaybackServiceConnection.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioPlaybackServiceConnection.kt new file mode 100644 index 00000000000000..6b933772051bcf --- /dev/null +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioPlaybackServiceConnection.kt @@ -0,0 +1,100 @@ +package expo.modules.audio.service + +import android.content.ComponentName +import android.os.IBinder +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi +import androidx.media3.session.MediaSessionService.SERVICE_INTERFACE +import expo.modules.audio.AudioPlayer +import expo.modules.audio.getPlaybackServiceErrorMessage +import expo.modules.kotlin.AppContext +import java.lang.ref.WeakReference + +class AudioPlaybackServiceBinder(val service: AudioControlsService) : android.os.Binder() + +@OptIn(UnstableApi::class) +class AudioPlaybackServiceConnection( + val player: WeakReference, + appContext: AppContext +) : BaseServiceConnection(appContext) { + var playbackServiceBinder: AudioPlaybackServiceBinder? = null + private set + + @Volatile + private var isReleased = false + + fun release() { + isReleased = true + } + + fun bindWithService() { + if (bindingState == ServiceBindingState.BOUND || bindingState == ServiceBindingState.BINDING || bindingState == ServiceBindingState.UNBINDING) { + return + } + + if (bindingState == ServiceBindingState.UNBOUND || bindingState == ServiceBindingState.FAILED) { + val reactContext = appContext.reactContext ?: run { + onBindingFailed("Binding with the expo-audio playback service failed: React context lost") + return + } + val serviceStarted = startServiceAndBind(appContext, reactContext, this, AudioControlsService::class.java, SERVICE_INTERFACE) + + if (!serviceStarted) { + onBindingFailed("Failed to start the expo-audio playback service.") + return + } + + transitionToState(ServiceBindingState.BINDING) + } + } + + override fun onServiceConnected(componentName: ComponentName, binder: IBinder) { + val player = player.get() + if (player == null || isReleased) { + transitionToState(ServiceBindingState.FAILED) + return + } + + val serviceBinder: AudioPlaybackServiceBinder = binder as? AudioPlaybackServiceBinder ?: run { + onBindingFailed("Could not bind to the playback service - invalid binder type") + transitionToState(ServiceBindingState.FAILED) + return + } + + transitionToState(ServiceBindingState.BOUND) + + playbackServiceBinder = serviceBinder + serviceBinder.service.appContext = appContext + + if (player.isActiveForLockScreen) { + serviceBinder.service.setPlayerOptions(player, player.metadata, player.lockScreenOptions) + } + } + + override fun onServiceDisconnected(componentName: ComponentName) { + playbackServiceBinder?.service?.let { service -> + service.playbackListener?.let { listener -> + val player = player.get() + if (player != null && !isReleased) { + player.ref.removeListener(listener) + } + } + service.playbackListener = null + } + + playbackServiceBinder = null + super.onServiceDisconnected(componentName) + } + + override fun onServiceDied() { + super.onServiceDied() + } + + override fun onServiceConnectedInternal(binder: AudioPlaybackServiceBinder) { + // NOOP + } + + override fun getServiceErrorMessage(message: String): String { + return getPlaybackServiceErrorMessage(message) + } +} diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingService.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingService.kt index 8328abb445a826..2c9230336efc5c 100644 --- a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingService.kt +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingService.kt @@ -8,37 +8,37 @@ import android.app.Service import android.content.Context import android.content.Intent import android.content.pm.ServiceInfo -import android.os.Binder import android.os.Build import android.os.IBinder import android.util.Log import androidx.core.app.NotificationCompat import expo.modules.audio.AudioRecorder +import expo.modules.audio.getRecordingServiceErrorMessage +import expo.modules.kotlin.AppContext import java.lang.ref.WeakReference private const val TAG = "AudioRecordingService" class AudioRecordingService : Service() { - private val binder = AudioRecordingBinder() - private var activeRecorders = mutableSetOf>() + private val binder = AudioRecordingServiceBinder(this) + private val activeRecorders = mutableSetOf>() + private val recorderLock = Any() private var notificationId = NOTIFICATION_ID - inner class AudioRecordingBinder : Binder() { - fun getService(): AudioRecordingService = this@AudioRecordingService - } + @Volatile + private var isRunningForeground = false + + private var weakContext: WeakReference? = null + var appContext: AppContext? + get() = weakContext?.get() + set(value) { + weakContext = value?.let { WeakReference(it) } + } override fun onCreate() { super.onCreate() Log.d(TAG, "Service onCreate()") - instance = this createNotificationChannelIfNeeded() - - synchronized(pendingRecorders) { - pendingRecorders.forEach { recorder -> - registerRecorder(recorder) - } - pendingRecorders.clear() - } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { @@ -65,6 +65,10 @@ class AudioRecordingService : Service() { NotificationManager.IMPORTANCE_LOW ).apply { description = "Shows when audio is being recorded in the background" + setShowBadge(false) + enableVibration(false) + enableLights(false) + setSound(null, null) } notificationManager.createNotificationChannel(channel) } @@ -103,6 +107,9 @@ class AudioRecordingService : Service() { stopPendingIntent ) .setCategory(NotificationCompat.CATEGORY_SERVICE) + .setSilent(true) + .setShowWhen(false) + .setVisibility(NotificationCompat.VISIBILITY_SECRET) // Hide from lock screen on secure devices .build() } @@ -119,32 +126,57 @@ class AudioRecordingService : Service() { } else { startForeground(notificationId, notification) } - } catch (_: Exception) { + isRunningForeground = true + } catch (e: Exception) { + appContext?.jsLogger?.error( + getRecordingServiceErrorMessage("Failed to start the expo-audio foreground service for background recording"), + e + ) + isRunningForeground = false } } + private fun stopForegroundWithNotification() { + stopForeground(STOP_FOREGROUND_REMOVE) + isRunningForeground = false + } + fun registerRecorder(recorder: AudioRecorder) { - activeRecorders.removeAll { it.get() == null } - activeRecorders.add(WeakReference(recorder)) + synchronized(recorderLock) { + activeRecorders.removeAll { it.get() == null } + + if (activeRecorders.any { it.get() === recorder }) { + return + } + + activeRecorders.add(WeakReference(recorder)) - if (activeRecorders.size == 1) { - startForegroundWithNotification() + if (activeRecorders.size == 1 || !isRunningForeground) { + startForegroundWithNotification() + } } } fun unregisterRecorder(recorder: AudioRecorder) { - activeRecorders.removeAll { it.get() == recorder || it.get() == null } + synchronized(recorderLock) { + activeRecorders.removeAll { it.get() == recorder || it.get() == null } - if (activeRecorders.isEmpty()) { - stopSelf() + if (activeRecorders.isEmpty()) { + stopForegroundWithNotification() + stopSelf() + } } } private fun stopRecordingAndService() { - activeRecorders.forEach { weakRef -> - weakRef.get()?.stopRecording() + synchronized(recorderLock) { + activeRecorders.forEach { weakRef -> + weakRef.get()?.stopRecording() + } + activeRecorders.clear() } - activeRecorders.clear() + + stopForegroundWithNotification() stopSelf() } @@ -154,48 +186,17 @@ class AudioRecordingService : Service() { override fun onDestroy() { super.onDestroy() - instance = null - activeRecorders.clear() + // Ensure notification is removed when service is destroyed + stopForegroundWithNotification() + synchronized(recorderLock) { + activeRecorders.clear() + } } companion object { private const val CHANNEL_ID = "expo_audio_recording_channel" private const val NOTIFICATION_ID = 2001 - private const val ACTION_START_RECORDING = "expo.modules.audio.action.START_RECORDING" - private const val ACTION_STOP_RECORDING = "expo.modules.audio.action.STOP_RECORDING" - - @Volatile - private var instance: AudioRecordingService? = null - private val pendingRecorders = mutableSetOf() - - fun getInstance(): AudioRecordingService? = instance - - fun startService(context: Context, recorder: AudioRecorder) { - val intent = Intent(context, AudioRecordingService::class.java).apply { - action = ACTION_START_RECORDING - } - - val service = getInstance() - if (service != null) { - service.registerRecorder(recorder) - } else { - synchronized(pendingRecorders) { - pendingRecorders.add(recorder) - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } - } - } - - fun stopService(context: Context) { - val intent = Intent(context, AudioRecordingService::class.java).apply { - action = ACTION_STOP_RECORDING - } - context.startService(intent) - } + internal const val ACTION_START_RECORDING = "expo.modules.audio.action.START_RECORDING" + internal const val ACTION_STOP_RECORDING = "expo.modules.audio.action.STOP_RECORDING" } } diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingServiceConnection.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingServiceConnection.kt new file mode 100644 index 00000000000000..28be72f2207e55 --- /dev/null +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingServiceConnection.kt @@ -0,0 +1,153 @@ +package expo.modules.audio.service + +import android.content.ComponentName +import android.os.IBinder +import expo.modules.audio.AudioRecorder +import expo.modules.audio.AudioRecordingServiceException +import expo.modules.audio.getRecordingServiceErrorMessage +import expo.modules.kotlin.AppContext +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.lang.ref.WeakReference +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class AudioRecordingServiceBinder(val service: AudioRecordingService) : android.os.Binder() + +class AudioRecordingServiceConnection( + val recorder: WeakReference, + appContext: AppContext +) : BaseServiceConnection(appContext) { + var recordingServiceBinder: AudioRecordingServiceBinder? = null + private set + private var bindingTimeoutJob: Job? = null + + @Volatile + private var isRecorderReleased = false + private var bindingContinuation: Continuation? = null + + fun release() { + isRecorderReleased = true + cancelBindingTimeout() + } + + fun startBindingTimeout(timeoutMs: Long = 5000) { // 5000ms is more or less the default Android system timeout for binding + bindingTimeoutJob?.cancel() + bindingTimeoutJob = CoroutineScope(Dispatchers.Default).launch { + delay(timeoutMs) + if (bindingState == ServiceBindingState.BINDING) { + bindingContinuation?.resumeWithException(AudioRecordingServiceException("The recording service connection has failed to connect with the recording service within ${timeoutMs}ms")) + unbind() + } + } + } + + private fun cancelBindingTimeout() { + bindingTimeoutJob?.cancel() + bindingTimeoutJob = null + } + + /** + * Binds with the recording service. If the service doesn't exist, it will create the service. + */ + suspend fun bindWithService() { + if (bindingState == ServiceBindingState.BOUND) { + return + } + + if (bindingState == ServiceBindingState.BINDING) { + throw AudioRecordingServiceException("Tried binding to the recording service while the previous attempt is still ongoing.") + } + + if (bindingState == ServiceBindingState.UNBINDING) { + throw AudioRecordingServiceException("Tried binding to the recording service while the unbinding process is ongoing.") + } + + suspendCoroutine { continuation -> + if (bindingState == ServiceBindingState.UNBOUND || bindingState == ServiceBindingState.FAILED) { + val reactContext = appContext.reactContext ?: run { + onBindingFailed("Binding with the expo-audio playback service failed: React context lost") + return@suspendCoroutine + } + val serviceRunning = startServiceAndBind(appContext, reactContext, this, AudioRecordingService::class.java, AudioRecordingService.ACTION_START_RECORDING) + + if (!serviceRunning) { + continuation.resumeWithException(AudioRecordingServiceException("Failed to start the recording service")) + return@suspendCoroutine + } + + transitionToState(ServiceBindingState.BINDING) + bindingContinuation = continuation + } + } + } + + override fun onServiceConnected(componentName: ComponentName, binder: IBinder) { + cancelBindingTimeout() + + val recorder = recorder.get() + if (recorder == null || isRecorderReleased) { + transitionToState(ServiceBindingState.FAILED) + bindingContinuation?.resumeWithException(AudioRecordingServiceException("The recorder has been deallocated")) + return + } + + val serviceBinder: AudioRecordingServiceBinder = binder as? AudioRecordingServiceBinder ?: run { + bindingContinuation?.resumeWithException(AudioRecordingServiceException("Could not bind to the recording service - invalid binder type")) + transitionToState(ServiceBindingState.FAILED) + return + } + transitionToState(ServiceBindingState.BOUND) + + bindingContinuation?.resume(Unit) + recordingServiceBinder = serviceBinder + serviceBinder.service.appContext = appContext + } + + override fun onServiceDisconnected(componentName: ComponentName) { + cancelBindingTimeout() + recordingServiceBinder = null + super.onServiceDisconnected(componentName) + } + + override fun onBindingDied(name: ComponentName?) { + cancelBindingTimeout() + bindingContinuation?.resumeWithException( + AudioRecordingServiceException("Service binding died") + ) + bindingContinuation = null + super.onBindingDied(name) + } + + override fun onNullBinding(componentName: ComponentName) { + cancelBindingTimeout() + bindingContinuation?.resumeWithException( + AudioRecordingServiceException("Service returned null binding") + ) + bindingContinuation = null + super.onNullBinding(componentName) + } + + override fun onServiceDied() { + cancelBindingTimeout() + recordingServiceBinder = null + super.onServiceDied() + } + + override fun onServiceConnectedInternal(binder: AudioRecordingServiceBinder) { + // Not used, handled in onServiceConnected above + } + + override fun getServiceErrorMessage(message: String): String { + return getRecordingServiceErrorMessage(message) + } + + fun cleanup() { + cancelBindingTimeout() + } +} diff --git a/packages/expo-audio/android/src/main/java/expo/modules/audio/service/BaseServiceConnection.kt b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/BaseServiceConnection.kt new file mode 100644 index 00000000000000..d3802fb8f16938 --- /dev/null +++ b/packages/expo-audio/android/src/main/java/expo/modules/audio/service/BaseServiceConnection.kt @@ -0,0 +1,141 @@ +package expo.modules.audio.service + +import android.app.Service +import android.content.ComponentName +import android.content.Context +import android.content.Context.BIND_AUTO_CREATE +import android.content.Context.BIND_INCLUDE_CAPABILITIES +import android.content.Intent +import android.content.ServiceConnection +import android.os.Build +import android.util.Log +import expo.modules.kotlin.AppContext +import expo.modules.kotlin.exception.Exceptions +import java.lang.ref.WeakReference + +enum class ServiceBindingState { + UNBOUND, + BINDING, + BOUND, + UNBINDING, + FAILED +} + +abstract class BaseServiceConnection(appContext: AppContext) : ServiceConnection { + @Volatile + private var _bindingState = ServiceBindingState.UNBOUND + + /** + * Current binding state of the service connection. + * This property is thread-safe and can be read from any thread. + */ + var bindingState: ServiceBindingState + get() = synchronized(this) { + _bindingState + } + set(value) = synchronized(this) { + _bindingState = value + } + + val isConnected: Boolean + get() = bindingState == ServiceBindingState.BOUND + + private val _appContext = WeakReference(appContext) + protected val appContext: AppContext + get() = _appContext.get() ?: throw Exceptions.AppContextLost() + + protected abstract fun onServiceConnectedInternal(binder: T) + protected abstract fun getServiceErrorMessage(message: String): String + + protected open fun onBindingFailed(message: String, reason: Throwable? = null) { + try { + appContext.jsLogger?.error(getServiceErrorMessage(message), reason) + } catch (e: Exception) { + Log.e(TAG, "Failed to log binding error: $message", e) + } + } + + protected open fun onServiceDied() { + try { + appContext.jsLogger?.error( + getServiceErrorMessage("Service died unexpectedly") + ) + } catch (e: Exception) { + Log.e(TAG, "Failed to log service death", e) + } + } + + fun transitionToState(newState: ServiceBindingState) { + bindingState = newState + } + + override fun onServiceDisconnected(componentName: ComponentName) { + bindingState = ServiceBindingState.UNBOUND + + onServiceDied() + } + + override fun onBindingDied(name: ComponentName?) { + bindingState = ServiceBindingState.UNBOUND + + onServiceDied() + super.onBindingDied(name) + } + + override fun onNullBinding(componentName: ComponentName) { + bindingState = ServiceBindingState.FAILED + + val errorMessage = "Could not bind to the service. " + + "Check AndroidManifest.xml for proper service and permission declarations." + onBindingFailed(errorMessage) + + super.onNullBinding(componentName) + } + + fun unbind() { + val shouldUnbind = + bindingState == ServiceBindingState.BOUND || bindingState == ServiceBindingState.BINDING + + if (shouldUnbind) { + bindingState = ServiceBindingState.UNBINDING + try { + appContext.reactContext?.unbindService(this) + } catch (e: IllegalArgumentException) { + // Service was never bound or already unbound - this is expected in some cases + Log.d(TAG, "Service was already unbound: ${e.message}") + } catch (e: Exception) { + appContext.jsLogger?.error("Unexpected error unbinding service: ${e.message}") + } finally { + bindingState = ServiceBindingState.UNBOUND + } + } + } + + companion object { + private const val TAG = "BaseServiceConnection" + + fun startServiceAndBind( + appContext: AppContext, + context: Context, + serviceConnection: ServiceConnection, + clazz: Class, + action: String + ): Boolean { + appContext.reactContext?.apply { + val intent = Intent(context, clazz) + intent.action = action + + startService(intent) + + val flags = if (Build.VERSION.SDK_INT >= 29) { + BIND_AUTO_CREATE or BIND_INCLUDE_CAPABILITIES + } else { + BIND_AUTO_CREATE + } + + return bindService(intent, serviceConnection, flags) + } + return false + } + } +} diff --git a/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index 9164c38ab47e88..469905e3de532a 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -1,71 +1,7 @@ import { PermissionResponse } from 'expo-modules-core'; -import { AudioMode, AudioPlayerOptions, AudioSource, AudioStatus, PitchCorrectionQuality, RecorderState, RecordingInput, RecordingOptions, RecordingStartOptions } from './Audio.types'; -import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; -export declare class AudioPlayerWeb extends globalThis.expo.SharedObject implements AudioPlayer { - constructor(source: AudioSource, options?: AudioPlayerOptions); - id: number; - isAudioSamplingSupported: boolean; - isBuffering: boolean; - shouldCorrectPitch: boolean; - private src; - private media; - private interval; - private isPlaying; - private loaded; - private crossOrigin?; - get playing(): boolean; - get muted(): boolean; - set muted(value: boolean); - get loop(): boolean; - set loop(value: boolean); - get duration(): number; - get currentTime(): number; - get paused(): boolean; - get isLoaded(): boolean; - get playbackRate(): number; - set playbackRate(value: number); - get volume(): number; - set volume(value: number); - get currentStatus(): AudioStatus; - play(): void; - pause(): void; - replace(source: AudioSource): void; - seekTo(seconds: number, toleranceMillisBefore?: number, toleranceMillisAfter?: number): Promise; - setAudioSamplingEnabled(enabled: boolean): void; - setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void; - remove(): void; - setActiveForLockScreen(active: boolean, metadata: Record): void; - updateLockScreenMetadata(metadata: Record): void; - clearLockScreenControls(): void; - _createMediaElement(): HTMLAudioElement; -} -export declare class AudioRecorderWeb extends globalThis.expo.SharedObject implements AudioRecorder { - constructor(options: Partial); - setup(): Promise; - id: number; - currentTime: number; - uri: string | null; - private options; - private mediaRecorder; - private mediaRecorderUptimeOfLastStartResume; - private mediaRecorderIsRecording; - private timeoutIds; - get isRecording(): boolean; - record(options?: RecordingStartOptions): void; - private startActualRecording; - getAvailableInputs(): RecordingInput[]; - getCurrentInput(): Promise; - prepareToRecordAsync(): Promise; - getStatus(): RecorderState; - pause(): void; - recordForDuration(seconds: number): void; - setInput(input: string): void; - startRecordingAtTime(seconds: number): void; - stop(): Promise; - clearTimeouts(): void; - private createMediaRecorder; - private getAudioRecorderDurationMillis; -} +import { AudioMode } from './Audio.types'; +export { AudioPlayerWeb } from './AudioPlayer.web'; +export { AudioRecorderWeb } from './AudioRecorder.web'; export declare function setAudioModeAsync(mode: AudioMode): Promise; export declare function setIsAudioActiveAsync(active: boolean): Promise; export declare function getRecordingPermissionsAsync(): Promise; diff --git a/packages/expo-audio/build/AudioModule.web.d.ts.map b/packages/expo-audio/build/AudioModule.web.d.ts.map index 0d663b084cd834..e7ea086300c150 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts.map +++ b/packages/expo-audio/build/AudioModule.web.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"AudioModule.web.d.ts","sourceRoot":"","sources":["../src/AudioModule.web.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"AudioModule.web.d.ts","sourceRoot":"","sources":["../src/AudioModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAuBvD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,SAAS,iBAAI;AAC3D,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,OAAO,iBAAI;AAE/D,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAoBhF;AAED,wBAAsB,gCAAgC,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAkBpF"} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioModule.web.js b/packages/expo-audio/build/AudioModule.web.js index 407e9e9aa29c4a..bb01e60afd32e7 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -1,11 +1,7 @@ -import { Asset } from 'expo-asset'; import { PermissionStatus } from 'expo-modules-core'; -import { PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE } from './AudioEventKeys'; -import { RecordingPresets } from './RecordingConstants'; -const nextId = (() => { - let id = 0; - return () => id++; -})(); +import { getUserMedia } from './AudioUtils.web'; +export { AudioPlayerWeb } from './AudioPlayer.web'; +export { AudioRecorderWeb } from './AudioRecorder.web'; async function getPermissionWithQueryAsync(name) { if (!navigator || !navigator.permissions || !navigator.permissions.query) return null; @@ -25,377 +21,6 @@ async function getPermissionWithQueryAsync(name) { return PermissionStatus.UNDETERMINED; } } -function getUserMedia(constraints) { - if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - return navigator.mediaDevices.getUserMedia(constraints); - } - // Some browsers partially implement mediaDevices. We can't just assign an object - // with getUserMedia as it would overwrite existing properties. - // Here, we will just add the getUserMedia property if it's missing. - // First get ahold of the legacy getUserMedia, if present - const getUserMedia = - // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia - navigator.getUserMedia || - navigator.webkitGetUserMedia || - navigator.mozGetUserMedia || - function () { - const error = new Error('Permission unimplemented'); - error.code = 0; - error.name = 'NotAllowedError'; - throw error; - }; - return new Promise((resolve, reject) => { - // TODO(@kitten): The types indicates that this is incorrect. - // Please check whether this is correct! - // @ts-expect-error: The `successCallback` doesn't match a `resolve` function - getUserMedia.call(navigator, constraints, resolve, reject); - }); -} -function getStatusFromMedia(media, id) { - const isPlaying = !!(media.currentTime > 0 && - !media.paused && - !media.ended && - media.readyState > 2); - const status = { - id, - isLoaded: true, - duration: media.duration, - currentTime: media.currentTime, - playbackState: '', - timeControlStatus: isPlaying ? 'playing' : 'paused', - reasonForWaitingToPlay: '', - playing: isPlaying, - didJustFinish: media.ended, - isBuffering: false, - playbackRate: media.playbackRate, - shouldCorrectPitch: true, - mute: media.muted, - loop: media.loop, - }; - return status; -} -export class AudioPlayerWeb extends globalThis.expo.SharedObject { - constructor(source, options = {}) { - super(); - const { updateInterval = 500, crossOrigin } = options; - this.src = source; - this.interval = Math.max(updateInterval, 1); - this.crossOrigin = crossOrigin; - this.media = this._createMediaElement(); - } - id = nextId(); - isAudioSamplingSupported = false; - isBuffering = false; - shouldCorrectPitch = false; - src = null; - media; - interval = 500; - isPlaying = false; - loaded = false; - crossOrigin; - get playing() { - return this.isPlaying; - } - get muted() { - return this.media.muted; - } - set muted(value) { - this.media.muted = value; - } - get loop() { - return this.media.loop; - } - set loop(value) { - this.media.loop = value; - } - get duration() { - return this.media.duration; - } - get currentTime() { - return this.media.currentTime; - } - get paused() { - return this.media.paused; - } - get isLoaded() { - return this.loaded; - } - get playbackRate() { - return this.media.playbackRate; - } - set playbackRate(value) { - this.media.playbackRate = value; - } - get volume() { - return this.media.volume; - } - set volume(value) { - this.media.volume = value; - } - get currentStatus() { - return getStatusFromMedia(this.media, this.id); - } - play() { - this.media.play(); - this.isPlaying = true; - } - pause() { - this.media.pause(); - this.isPlaying = false; - } - replace(source) { - const wasPlaying = this.isPlaying; - // we need to remove the current media element and create a new one - this.remove(); - this.src = source; - this.isPlaying = false; - this.loaded = false; - this.media = this._createMediaElement(); - // Resume playback if it was playing before - if (wasPlaying) { - this.play(); - } - } - async seekTo(seconds, toleranceMillisBefore, toleranceMillisAfter) { - this.media.currentTime = seconds; - } - // Not supported on web - setAudioSamplingEnabled(enabled) { - this.isAudioSamplingSupported = false; - } - setPlaybackRate(second, pitchCorrectionQuality) { - this.media.playbackRate = second; - this.shouldCorrectPitch = pitchCorrectionQuality === 'high'; - this.media.preservesPitch = this.shouldCorrectPitch; - } - remove() { - this.media.pause(); - this.media.removeAttribute('src'); - this.media.load(); - getStatusFromMedia(this.media, this.id); - } - setActiveForLockScreen(active, metadata) { } - updateLockScreenMetadata(metadata) { } - clearLockScreenControls() { } - _createMediaElement() { - const newSource = getSourceUri(this.src); - const media = new Audio(newSource); - if (this.crossOrigin !== undefined) { - media.crossOrigin = this.crossOrigin; - } - let lastEmitTime = 0; - const intervalSec = this.interval / 1000; - // Throttled status updates based on interval - media.ontimeupdate = () => { - const now = media.currentTime; - // Handle backwards time (loop/seek) - if (now < lastEmitTime) { - lastEmitTime = now; - } - if (now - lastEmitTime >= intervalSec) { - lastEmitTime = now; - this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); - } - }; - media.onplay = () => { - this.isPlaying = true; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - playing: this.isPlaying, - }); - }; - media.onpause = () => { - this.isPlaying = false; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - playing: this.isPlaying, - }); - }; - media.onseeked = () => { - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); - }; - media.onended = () => { - lastEmitTime = 0; - }; - media.onloadeddata = () => { - this.loaded = true; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - isLoaded: this.loaded, - }); - }; - return media; - } -} -function getSourceUri(source) { - if (typeof source === 'string') { - return source; - } - if (typeof source === 'number') { - const asset = Asset.fromModule(source); - return asset.uri; - } - if (typeof source?.assetId === 'number' && !source?.uri) { - const asset = Asset.fromModule(source.assetId); - return asset.uri; - } - return source?.uri ?? undefined; -} -export class AudioRecorderWeb extends globalThis.expo.SharedObject { - constructor(options) { - super(); - this.options = options; - } - async setup() { - this.mediaRecorder = await this.createMediaRecorder(this.options); - } - id = nextId(); - currentTime = 0; - uri = null; - options; - mediaRecorder = null; - mediaRecorderUptimeOfLastStartResume = 0; - mediaRecorderIsRecording = false; - timeoutIds = []; - get isRecording() { - return this.mediaRecorder?.state === 'recording'; - } - record(options) { - if (this.mediaRecorder === null) { - throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); - } - // Clear any existing timeouts - this.clearTimeouts(); - // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely - // Only forDuration is implemented using setTimeout - const { forDuration } = options || {}; - this.startActualRecording(); - if (forDuration !== undefined) { - this.timeoutIds.push(setTimeout(() => { - this.stop(); - }, forDuration * 1000)); - } - } - startActualRecording() { - if (this.mediaRecorder?.state === 'paused') { - this.mediaRecorder.resume(); - } - else { - this.mediaRecorder?.start(); - } - } - getAvailableInputs() { - return []; - } - getCurrentInput() { - return Promise.resolve({ - type: 'Default', - name: 'Default', - uid: 'Default', - }); - } - async prepareToRecordAsync() { - return this.setup(); - } - getStatus() { - return { - canRecord: this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive', - isRecording: this.mediaRecorder?.state === 'recording', - durationMillis: this.getAudioRecorderDurationMillis(), - mediaServicesDidReset: false, - url: this.uri, - }; - } - pause() { - if (this.mediaRecorder === null) { - throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); - } - this.mediaRecorder?.pause(); - } - recordForDuration(seconds) { - this.record({ forDuration: seconds }); - } - setInput(input) { } - startRecordingAtTime(seconds) { - this.record({ atTime: seconds }); - } - async stop() { - if (this.mediaRecorder === null) { - throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); - } - const dataPromise = new Promise((resolve) => this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data))); - this.mediaRecorder?.stop(); - this.mediaRecorder = null; - const data = await dataPromise; - const url = URL.createObjectURL(data); - this.uri = url; - this.emit(RECORDING_STATUS_UPDATE, { - id: this.id, - isFinished: true, - hasError: false, - error: null, - url, - }); - } - clearTimeouts() { - this.timeoutIds.forEach((id) => clearTimeout(id)); - } - async createMediaRecorder(options) { - if (typeof navigator !== 'undefined' && !navigator.mediaDevices) { - throw new Error('No media devices available'); - } - this.mediaRecorderUptimeOfLastStartResume = 0; - this.currentTime = 0; - const stream = await getUserMedia({ audio: true }); - const defaults = RecordingPresets.HIGH_QUALITY.web; - const mediaRecorderOptions = {}; - const mimeType = options.mimeType ?? defaults.mimeType; - if (mimeType && MediaRecorder.isTypeSupported(mimeType)) { - mediaRecorderOptions.mimeType = mimeType; - } - if (options.bitsPerSecond) { - mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond; - } - else if (options.bitRate) { - mediaRecorderOptions.audioBitsPerSecond = options.bitRate; - } - else { - mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond; - } - const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions); - mediaRecorder.addEventListener('pause', () => { - this.currentTime = this.getAudioRecorderDurationMillis(); - this.mediaRecorderIsRecording = false; - }); - mediaRecorder.addEventListener('resume', () => { - this.mediaRecorderUptimeOfLastStartResume = Date.now(); - this.mediaRecorderIsRecording = true; - }); - mediaRecorder.addEventListener('start', () => { - this.mediaRecorderUptimeOfLastStartResume = Date.now(); - this.currentTime = 0; - this.mediaRecorderIsRecording = true; - }); - mediaRecorder?.addEventListener('stop', () => { - this.currentTime = 0; - this.mediaRecorderIsRecording = false; - // Clears recording icon in Chrome tab - stream.getTracks().forEach((track) => track.stop()); - }); - return mediaRecorder; - } - getAudioRecorderDurationMillis() { - let duration = this.currentTime; - if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { - duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume; - } - return duration; - } -} export async function setAudioModeAsync(mode) { } export async function setIsAudioActiveAsync(active) { } export async function getRecordingPermissionsAsync() { diff --git a/packages/expo-audio/build/AudioModule.web.js.map b/packages/expo-audio/build/AudioModule.web.js.map index 535c047ccfc98f..822852a50d37b3 100644 --- a/packages/expo-audio/build/AudioModule.web.js.map +++ b/packages/expo-audio/build/AudioModule.web.js.map @@ -1 +1 @@ -{"version":3,"file":"AudioModule.web.js","sourceRoot":"","sources":["../src/AudioModule.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { Asset } from 'expo-asset';\nimport { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport {\n AudioMode,\n AudioPlayerOptions,\n AudioSource,\n AudioStatus,\n PitchCorrectionQuality,\n RecorderState,\n RecordingInput,\n RecordingOptions,\n RecordingOptionsWeb,\n RecordingStartOptions,\n} from './Audio.types';\nimport { PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE } from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nasync function getPermissionWithQueryAsync(\n name: PermissionNameWithAdditionalValues\n): Promise {\n if (!navigator || !navigator.permissions || !navigator.permissions.query) return null;\n\n try {\n const { state } = await navigator.permissions.query({ name });\n switch (state) {\n case 'granted':\n return PermissionStatus.GRANTED;\n case 'denied':\n return PermissionStatus.DENIED;\n default:\n return PermissionStatus.UNDETERMINED;\n }\n } catch {\n // Firefox - TypeError: 'microphone' (value of 'name' member of PermissionDescriptor) is not a valid value for enumeration PermissionName.\n return PermissionStatus.UNDETERMINED;\n }\n}\n\nfunction getUserMedia(constraints: MediaStreamConstraints): Promise {\n if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n return navigator.mediaDevices.getUserMedia(constraints);\n }\n\n // Some browsers partially implement mediaDevices. We can't just assign an object\n // with getUserMedia as it would overwrite existing properties.\n // Here, we will just add the getUserMedia property if it's missing.\n\n // First get ahold of the legacy getUserMedia, if present\n const getUserMedia =\n // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia\n navigator.getUserMedia ||\n navigator.webkitGetUserMedia ||\n navigator.mozGetUserMedia ||\n function () {\n const error: any = new Error('Permission unimplemented');\n error.code = 0;\n error.name = 'NotAllowedError';\n throw error;\n };\n\n return new Promise((resolve, reject) => {\n // TODO(@kitten): The types indicates that this is incorrect.\n // Please check whether this is correct!\n // @ts-expect-error: The `successCallback` doesn't match a `resolve` function\n getUserMedia.call(navigator, constraints, resolve, reject);\n });\n}\n\nfunction getStatusFromMedia(media: HTMLMediaElement, id: number): AudioStatus {\n const isPlaying = !!(\n media.currentTime > 0 &&\n !media.paused &&\n !media.ended &&\n media.readyState > 2\n );\n\n const status: AudioStatus = {\n id,\n isLoaded: true,\n duration: media.duration,\n currentTime: media.currentTime,\n playbackState: '',\n timeControlStatus: isPlaying ? 'playing' : 'paused',\n reasonForWaitingToPlay: '',\n playing: isPlaying,\n didJustFinish: media.ended,\n isBuffering: false,\n playbackRate: media.playbackRate,\n shouldCorrectPitch: true,\n mute: media.muted,\n loop: media.loop,\n };\n\n return status;\n}\n\nexport class AudioPlayerWeb\n extends globalThis.expo.SharedObject\n implements AudioPlayer\n{\n constructor(source: AudioSource, options: AudioPlayerOptions = {}) {\n super();\n const { updateInterval = 500, crossOrigin } = options;\n this.src = source;\n this.interval = Math.max(updateInterval, 1);\n this.crossOrigin = crossOrigin;\n this.media = this._createMediaElement();\n }\n\n id: number = nextId();\n isAudioSamplingSupported = false;\n isBuffering = false;\n shouldCorrectPitch = false;\n\n private src: AudioSource = null;\n private media: HTMLAudioElement;\n private interval = 500;\n private isPlaying = false;\n private loaded = false;\n private crossOrigin?: 'anonymous' | 'use-credentials';\n\n get playing(): boolean {\n return this.isPlaying;\n }\n\n get muted(): boolean {\n return this.media.muted;\n }\n\n set muted(value: boolean) {\n this.media.muted = value;\n }\n\n get loop(): boolean {\n return this.media.loop;\n }\n\n set loop(value: boolean) {\n this.media.loop = value;\n }\n\n get duration(): number {\n return this.media.duration;\n }\n\n get currentTime(): number {\n return this.media.currentTime;\n }\n\n get paused(): boolean {\n return this.media.paused;\n }\n\n get isLoaded(): boolean {\n return this.loaded;\n }\n\n get playbackRate(): number {\n return this.media.playbackRate;\n }\n\n set playbackRate(value: number) {\n this.media.playbackRate = value;\n }\n\n get volume(): number {\n return this.media.volume;\n }\n\n set volume(value: number) {\n this.media.volume = value;\n }\n\n get currentStatus(): AudioStatus {\n return getStatusFromMedia(this.media, this.id);\n }\n\n play(): void {\n this.media.play();\n this.isPlaying = true;\n }\n\n pause(): void {\n this.media.pause();\n this.isPlaying = false;\n }\n\n replace(source: AudioSource): void {\n const wasPlaying = this.isPlaying;\n\n // we need to remove the current media element and create a new one\n this.remove();\n\n this.src = source;\n this.isPlaying = false;\n this.loaded = false;\n this.media = this._createMediaElement();\n\n // Resume playback if it was playing before\n if (wasPlaying) {\n this.play();\n }\n }\n\n async seekTo(\n seconds: number,\n toleranceMillisBefore?: number,\n toleranceMillisAfter?: number\n ): Promise {\n this.media.currentTime = seconds;\n }\n\n // Not supported on web\n setAudioSamplingEnabled(enabled: boolean): void {\n this.isAudioSamplingSupported = false;\n }\n\n setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void {\n this.media.playbackRate = second;\n this.shouldCorrectPitch = pitchCorrectionQuality === 'high';\n this.media.preservesPitch = this.shouldCorrectPitch;\n }\n\n remove(): void {\n this.media.pause();\n this.media.removeAttribute('src');\n this.media.load();\n getStatusFromMedia(this.media, this.id);\n }\n\n setActiveForLockScreen(active: boolean, metadata: Record): void {}\n updateLockScreenMetadata(metadata: Record): void {}\n clearLockScreenControls(): void {}\n\n _createMediaElement(): HTMLAudioElement {\n const newSource = getSourceUri(this.src);\n const media = new Audio(newSource);\n if (this.crossOrigin !== undefined) {\n media.crossOrigin = this.crossOrigin;\n }\n\n let lastEmitTime = 0;\n const intervalSec = this.interval / 1000;\n\n // Throttled status updates based on interval\n media.ontimeupdate = () => {\n const now = media.currentTime;\n // Handle backwards time (loop/seek)\n if (now < lastEmitTime) {\n lastEmitTime = now;\n }\n if (now - lastEmitTime >= intervalSec) {\n lastEmitTime = now;\n this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id));\n }\n };\n\n media.onplay = () => {\n this.isPlaying = true;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n playing: this.isPlaying,\n });\n };\n\n media.onpause = () => {\n this.isPlaying = false;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n playing: this.isPlaying,\n });\n };\n\n media.onseeked = () => {\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id));\n };\n\n media.onended = () => {\n lastEmitTime = 0;\n };\n\n media.onloadeddata = () => {\n this.loaded = true;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n isLoaded: this.loaded,\n });\n };\n\n return media;\n }\n}\n\nfunction getSourceUri(source: AudioSource): string | undefined {\n if (typeof source === 'string') {\n return source;\n }\n if (typeof source === 'number') {\n const asset = Asset.fromModule(source);\n return asset.uri;\n }\n if (typeof source?.assetId === 'number' && !source?.uri) {\n const asset = Asset.fromModule(source.assetId);\n return asset.uri;\n }\n\n return source?.uri ?? undefined;\n}\n\nexport class AudioRecorderWeb\n extends globalThis.expo.SharedObject\n implements AudioRecorder\n{\n constructor(options: Partial) {\n super();\n this.options = options;\n }\n\n async setup() {\n this.mediaRecorder = await this.createMediaRecorder(this.options);\n }\n\n id = nextId();\n currentTime = 0;\n uri: string | null = null;\n\n private options: Partial;\n private mediaRecorder: MediaRecorder | null = null;\n private mediaRecorderUptimeOfLastStartResume = 0;\n private mediaRecorderIsRecording = false;\n private timeoutIds: number[] = [];\n\n get isRecording(): boolean {\n return this.mediaRecorder?.state === 'recording';\n }\n\n record(options?: RecordingStartOptions): void {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n // Clear any existing timeouts\n this.clearTimeouts();\n\n // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely\n // Only forDuration is implemented using setTimeout\n const { forDuration } = options || {};\n\n this.startActualRecording();\n\n if (forDuration !== undefined) {\n this.timeoutIds.push(\n setTimeout(() => {\n this.stop();\n }, forDuration * 1000)\n );\n }\n }\n\n private startActualRecording(): void {\n if (this.mediaRecorder?.state === 'paused') {\n this.mediaRecorder.resume();\n } else {\n this.mediaRecorder?.start();\n }\n }\n\n getAvailableInputs(): RecordingInput[] {\n return [];\n }\n\n getCurrentInput(): Promise {\n return Promise.resolve({\n type: 'Default',\n name: 'Default',\n uid: 'Default',\n });\n }\n\n async prepareToRecordAsync(): Promise {\n return this.setup();\n }\n\n getStatus(): RecorderState {\n return {\n canRecord:\n this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive',\n isRecording: this.mediaRecorder?.state === 'recording',\n durationMillis: this.getAudioRecorderDurationMillis(),\n mediaServicesDidReset: false,\n url: this.uri,\n };\n }\n\n pause(): void {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n this.mediaRecorder?.pause();\n }\n\n recordForDuration(seconds: number): void {\n this.record({ forDuration: seconds });\n }\n\n setInput(input: string): void {}\n\n startRecordingAtTime(seconds: number): void {\n this.record({ atTime: seconds });\n }\n\n async stop(): Promise {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n const dataPromise = new Promise((resolve) =>\n this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data))\n );\n\n this.mediaRecorder?.stop();\n this.mediaRecorder = null;\n\n const data = await dataPromise;\n const url = URL.createObjectURL(data);\n\n this.uri = url;\n\n this.emit(RECORDING_STATUS_UPDATE, {\n id: this.id,\n isFinished: true,\n hasError: false,\n error: null,\n url,\n });\n }\n\n clearTimeouts() {\n this.timeoutIds.forEach((id) => clearTimeout(id));\n }\n\n private async createMediaRecorder(\n options: Partial & Partial\n ): Promise {\n if (typeof navigator !== 'undefined' && !navigator.mediaDevices) {\n throw new Error('No media devices available');\n }\n\n this.mediaRecorderUptimeOfLastStartResume = 0;\n this.currentTime = 0;\n\n const stream = await getUserMedia({ audio: true });\n\n const defaults = RecordingPresets.HIGH_QUALITY.web;\n const mediaRecorderOptions: MediaRecorderOptions = {};\n\n const mimeType = options.mimeType ?? defaults.mimeType;\n if (mimeType && MediaRecorder.isTypeSupported(mimeType)) {\n mediaRecorderOptions.mimeType = mimeType;\n }\n\n if (options.bitsPerSecond) {\n mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond;\n } else if (options.bitRate) {\n mediaRecorderOptions.audioBitsPerSecond = options.bitRate;\n } else {\n mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond;\n }\n\n const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions);\n\n mediaRecorder.addEventListener('pause', () => {\n this.currentTime = this.getAudioRecorderDurationMillis();\n this.mediaRecorderIsRecording = false;\n });\n\n mediaRecorder.addEventListener('resume', () => {\n this.mediaRecorderUptimeOfLastStartResume = Date.now();\n this.mediaRecorderIsRecording = true;\n });\n\n mediaRecorder.addEventListener('start', () => {\n this.mediaRecorderUptimeOfLastStartResume = Date.now();\n this.currentTime = 0;\n this.mediaRecorderIsRecording = true;\n });\n\n mediaRecorder?.addEventListener('stop', () => {\n this.currentTime = 0;\n this.mediaRecorderIsRecording = false;\n\n // Clears recording icon in Chrome tab\n stream.getTracks().forEach((track) => track.stop());\n });\n\n return mediaRecorder;\n }\n\n private getAudioRecorderDurationMillis() {\n let duration = this.currentTime;\n if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) {\n duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume;\n }\n return duration;\n }\n}\n\nexport async function setAudioModeAsync(mode: AudioMode) {}\nexport async function setIsAudioActiveAsync(active: boolean) {}\n\nexport async function getRecordingPermissionsAsync(): Promise {\n const maybeStatus = await getPermissionWithQueryAsync('microphone');\n switch (maybeStatus) {\n case PermissionStatus.GRANTED:\n return {\n status: PermissionStatus.GRANTED,\n expires: 'never',\n canAskAgain: true,\n granted: true,\n };\n case PermissionStatus.DENIED:\n return {\n status: PermissionStatus.DENIED,\n expires: 'never',\n canAskAgain: true,\n granted: false,\n };\n default:\n return await requestRecordingPermissionsAsync();\n }\n}\n\nexport async function requestRecordingPermissionsAsync(): Promise {\n try {\n const stream = await getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => track.stop());\n return {\n status: PermissionStatus.GRANTED,\n expires: 'never',\n canAskAgain: true,\n granted: true,\n };\n } catch {\n return {\n status: PermissionStatus.DENIED,\n expires: 'never',\n canAskAgain: true,\n granted: false,\n };\n }\n}\n"]} \ No newline at end of file +{"version":3,"file":"AudioModule.web.js","sourceRoot":"","sources":["../src/AudioModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGzE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,KAAK,UAAU,2BAA2B,CACxC,IAAwC;IAExC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAEtF,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,SAAS;gBACZ,OAAO,gBAAgB,CAAC,OAAO,CAAC;YAClC,KAAK,QAAQ;gBACX,OAAO,gBAAgB,CAAC,MAAM,CAAC;YACjC;gBACE,OAAO,gBAAgB,CAAC,YAAY,CAAC;QACzC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0IAA0I;QAC1I,OAAO,gBAAgB,CAAC,YAAY,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAe,IAAG,CAAC;AAC3D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAe,IAAG,CAAC;AAE/D,MAAM,CAAC,KAAK,UAAU,4BAA4B;IAChD,MAAM,WAAW,GAAG,MAAM,2BAA2B,CAAC,YAAY,CAAC,CAAC;IACpE,QAAQ,WAAW,EAAE,CAAC;QACpB,KAAK,gBAAgB,CAAC,OAAO;YAC3B,OAAO;gBACL,MAAM,EAAE,gBAAgB,CAAC,OAAO;gBAChC,OAAO,EAAE,OAAO;gBAChB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,KAAK,gBAAgB,CAAC,MAAM;YAC1B,OAAO;gBACL,MAAM,EAAE,gBAAgB,CAAC,MAAM;gBAC/B,OAAO,EAAE,OAAO;gBAChB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,KAAK;aACf,CAAC;QACJ;YACE,OAAO,MAAM,gCAAgC,EAAE,CAAC;IACpD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gCAAgC;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,OAAO;YACL,MAAM,EAAE,gBAAgB,CAAC,OAAO;YAChC,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,MAAM,EAAE,gBAAgB,CAAC,MAAM;YAC/B,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,KAAK;SACf,CAAC;IACJ,CAAC;AACH,CAAC","sourcesContent":["import { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport { AudioMode } from './Audio.types';\nimport { getUserMedia } from './AudioUtils.web';\n\nexport { AudioPlayerWeb } from './AudioPlayer.web';\nexport { AudioRecorderWeb } from './AudioRecorder.web';\n\nasync function getPermissionWithQueryAsync(\n name: PermissionNameWithAdditionalValues\n): Promise {\n if (!navigator || !navigator.permissions || !navigator.permissions.query) return null;\n\n try {\n const { state } = await navigator.permissions.query({ name });\n switch (state) {\n case 'granted':\n return PermissionStatus.GRANTED;\n case 'denied':\n return PermissionStatus.DENIED;\n default:\n return PermissionStatus.UNDETERMINED;\n }\n } catch {\n // Firefox - TypeError: 'microphone' (value of 'name' member of PermissionDescriptor) is not a valid value for enumeration PermissionName.\n return PermissionStatus.UNDETERMINED;\n }\n}\n\nexport async function setAudioModeAsync(mode: AudioMode) {}\nexport async function setIsAudioActiveAsync(active: boolean) {}\n\nexport async function getRecordingPermissionsAsync(): Promise {\n const maybeStatus = await getPermissionWithQueryAsync('microphone');\n switch (maybeStatus) {\n case PermissionStatus.GRANTED:\n return {\n status: PermissionStatus.GRANTED,\n expires: 'never',\n canAskAgain: true,\n granted: true,\n };\n case PermissionStatus.DENIED:\n return {\n status: PermissionStatus.DENIED,\n expires: 'never',\n canAskAgain: true,\n granted: false,\n };\n default:\n return await requestRecordingPermissionsAsync();\n }\n}\n\nexport async function requestRecordingPermissionsAsync(): Promise {\n try {\n const stream = await getUserMedia({ audio: true });\n stream.getTracks().forEach((track) => track.stop());\n return {\n status: PermissionStatus.GRANTED,\n expires: 'never',\n canAskAgain: true,\n granted: true,\n };\n } catch {\n return {\n status: PermissionStatus.DENIED,\n expires: 'never',\n canAskAgain: true,\n granted: false,\n };\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioPlayer.web.d.ts b/packages/expo-audio/build/AudioPlayer.web.d.ts new file mode 100644 index 00000000000000..7cf9ccc2153182 --- /dev/null +++ b/packages/expo-audio/build/AudioPlayer.web.d.ts @@ -0,0 +1,47 @@ +import { AudioMetadata, AudioPlayerOptions, AudioSource, AudioStatus, PitchCorrectionQuality } from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; +import { AudioPlayer, AudioEvents } from './AudioModule.types'; +export declare class AudioPlayerWeb extends globalThis.expo.SharedObject implements AudioPlayer { + constructor(source: AudioSource, options?: AudioPlayerOptions); + id: number; + isAudioSamplingSupported: boolean; + isBuffering: boolean; + shouldCorrectPitch: boolean; + private src; + private media; + private interval; + private isPlaying; + private loaded; + private crossOrigin?; + private analyser; + private sourceNode; + private samplingFrameId; + private samplingEnabled; + get playing(): boolean; + get muted(): boolean; + set muted(value: boolean); + get loop(): boolean; + set loop(value: boolean); + get duration(): number; + get currentTime(): number; + get paused(): boolean; + get isLoaded(): boolean; + get playbackRate(): number; + set playbackRate(value: number); + get volume(): number; + set volume(value: number); + get currentStatus(): AudioStatus; + play(): void; + pause(): void; + replace(source: AudioSource): void; + seekTo(seconds: number, toleranceMillisBefore?: number, toleranceMillisAfter?: number): Promise; + setAudioSamplingEnabled(enabled: boolean): void; + setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void; + remove(): void; + setActiveForLockScreen(active: boolean, metadata?: AudioMetadata, options?: AudioLockScreenOptions): void; + updateLockScreenMetadata(metadata: AudioMetadata): void; + clearLockScreenControls(): void; + _isCrossOrigin(): boolean; + _createMediaElement(): HTMLAudioElement; +} +//# sourceMappingURL=AudioPlayer.web.d.ts.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioPlayer.web.d.ts.map b/packages/expo-audio/build/AudioPlayer.web.d.ts.map new file mode 100644 index 00000000000000..f589a9a616f295 --- /dev/null +++ b/packages/expo-audio/build/AudioPlayer.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioPlayer.web.d.ts","sourceRoot":"","sources":["../src/AudioPlayer.web.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,sBAAsB,EACvB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAI/D,qBAAa,cACX,SAAQ,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAChD,YAAW,WAAW;gBAEV,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB;IASjE,EAAE,EAAE,MAAM,CAAY;IACtB,wBAAwB,UAAS;IACjC,WAAW,UAAS;IACpB,kBAAkB,UAAS;IAE3B,OAAO,CAAC,GAAG,CAAqB;IAChC,OAAO,CAAC,KAAK,CAAmB;IAChC,OAAO,CAAC,QAAQ,CAAO;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAC,CAAkC;IACtD,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,UAAU,CAA4C;IAC9D,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,eAAe,CAAS;IAEhC,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,IAAI,IAAI,OAAO,CAElB;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,OAAO,EAEtB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,MAAM,EAE7B;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAEvB;IAED,IAAI,aAAa,IAAI,WAAW,CAE/B;IAED,IAAI,IAAI,IAAI;IAKZ,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IA+B5B,MAAM,CACV,OAAO,EAAE,MAAM,EACf,qBAAqB,CAAC,EAAE,MAAM,EAC9B,oBAAoB,CAAC,EAAE,MAAM,GAC5B,OAAO,CAAC,IAAI,CAAC;IAIhB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAmE/C,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,sBAAsB,CAAC,EAAE,sBAAsB,GAAG,IAAI;IAOtF,MAAM,IAAI,IAAI;IAyBd,sBAAsB,CACpB,MAAM,EAAE,OAAO,EACf,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI;IAQP,wBAAwB,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI;IAIvD,uBAAuB,IAAI,IAAI;IAI/B,cAAc,IAAI,OAAO;IAQzB,mBAAmB,IAAI,gBAAgB;CAqExC"} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioPlayer.web.js b/packages/expo-audio/build/AudioPlayer.web.js new file mode 100644 index 00000000000000..831c472741e550 --- /dev/null +++ b/packages/expo-audio/build/AudioPlayer.web.js @@ -0,0 +1,267 @@ +import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE } from './AudioEventKeys'; +import { getAudioContext, getSourceUri, getStatusFromMedia, nextId } from './AudioUtils.web'; +import { mediaSessionController } from './MediaSessionController.web'; +export class AudioPlayerWeb extends globalThis.expo.SharedObject { + constructor(source, options = {}) { + super(); + const { updateInterval = 500, crossOrigin } = options; + this.src = source; + this.interval = Math.max(updateInterval, 1); + this.crossOrigin = crossOrigin; + this.media = this._createMediaElement(); + } + id = nextId(); + isAudioSamplingSupported = false; + isBuffering = false; + shouldCorrectPitch = false; + src = null; + media; + interval = 500; + isPlaying = false; + loaded = false; + crossOrigin; + analyser = null; + sourceNode = null; + samplingFrameId = null; + samplingEnabled = false; + get playing() { + return this.isPlaying; + } + get muted() { + return this.media.muted; + } + set muted(value) { + this.media.muted = value; + } + get loop() { + return this.media.loop; + } + set loop(value) { + this.media.loop = value; + } + get duration() { + return this.media.duration; + } + get currentTime() { + return this.media.currentTime; + } + get paused() { + return this.media.paused; + } + get isLoaded() { + return this.loaded; + } + get playbackRate() { + return this.media.playbackRate; + } + set playbackRate(value) { + this.media.playbackRate = value; + } + get volume() { + return this.media.volume; + } + set volume(value) { + this.media.volume = value; + } + get currentStatus() { + return getStatusFromMedia(this.media, this.id); + } + play() { + this.media.play(); + this.isPlaying = true; + } + pause() { + this.media.pause(); + this.isPlaying = false; + } + replace(source) { + const wasPlaying = this.isPlaying; + const wasSampling = this.samplingEnabled; + const mediaSessionState = mediaSessionController.getActiveState(this); + // we need to remove the current media element and create a new one + this.remove(); + this.src = source; + this.isPlaying = false; + this.loaded = false; + this.media = this._createMediaElement(); + if (wasSampling) { + this.setAudioSamplingEnabled(true); + } + if (mediaSessionState) { + mediaSessionController.setActivePlayer(this, mediaSessionState.metadata ?? undefined, mediaSessionState.options ?? undefined); + } + // Resume playback if it was playing before + if (wasPlaying) { + this.play(); + } + } + async seekTo(seconds, toleranceMillisBefore, toleranceMillisAfter) { + this.media.currentTime = seconds; + } + setAudioSamplingEnabled(enabled) { + if (enabled) { + if (!this.media.crossOrigin && this._isCrossOrigin()) { + this.isAudioSamplingSupported = false; + return; + } + if (this.analyser) { + return; + } + const ctx = getAudioContext(); + if (ctx.state === 'suspended') { + ctx.resume(); + } + if (!this.sourceNode) { + this.sourceNode = ctx.createMediaElementSource(this.media); + } + this.analyser = ctx.createAnalyser(); + this.analyser.fftSize = 2048; + this.sourceNode.disconnect(); + this.sourceNode.connect(this.analyser); + this.analyser.connect(ctx.destination); + const buffer = new Float32Array(this.analyser.frequencyBinCount); + const sampleLoop = () => { + if (!this.analyser) { + return; + } + if (this.isPlaying) { + this.analyser.getFloatTimeDomainData(buffer); + this.emit(AUDIO_SAMPLE_UPDATE, { + channels: [{ frames: Array.from(buffer) }], + timestamp: this.media.currentTime, + }); + } + this.samplingFrameId = requestAnimationFrame(sampleLoop); + }; + this.samplingFrameId = requestAnimationFrame(sampleLoop); + this.samplingEnabled = true; + this.isAudioSamplingSupported = true; + } + else { + if (this.samplingFrameId != null) { + cancelAnimationFrame(this.samplingFrameId); + this.samplingFrameId = null; + } + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + } + if (this.sourceNode) { + const ctx = getAudioContext(); + this.sourceNode.disconnect(); + this.sourceNode.connect(ctx.destination); + } + this.samplingEnabled = false; + } + } + setPlaybackRate(second, pitchCorrectionQuality) { + this.media.playbackRate = second; + this.shouldCorrectPitch = pitchCorrectionQuality === 'high'; + this.media.preservesPitch = this.shouldCorrectPitch; + mediaSessionController.updatePositionState(this); + } + remove() { + mediaSessionController.clear(this); + if (this.samplingFrameId != null) { + cancelAnimationFrame(this.samplingFrameId); + this.samplingFrameId = null; + } + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + } + if (this.sourceNode) { + this.sourceNode.disconnect(); + this.sourceNode = null; + } + this.samplingEnabled = false; + this.media.pause(); + this.media.removeAttribute('src'); + this.media.load(); + getStatusFromMedia(this.media, this.id); + } + setActiveForLockScreen(active, metadata, options) { + if (active) { + mediaSessionController.setActivePlayer(this, metadata, options); + } + else { + mediaSessionController.clear(this); + } + } + updateLockScreenMetadata(metadata) { + mediaSessionController.updateMetadata(this, metadata); + } + clearLockScreenControls() { + mediaSessionController.clear(this); + } + _isCrossOrigin() { + try { + return new URL(this.media.src).origin !== window.location.origin; + } + catch { + return false; + } + } + _createMediaElement() { + const newSource = getSourceUri(this.src); + const media = new Audio(newSource); + if (this.crossOrigin !== undefined) { + media.crossOrigin = this.crossOrigin; + } + let lastEmitTime = 0; + const intervalSec = this.interval / 1000; + // Throttled status updates based on interval + media.ontimeupdate = () => { + const now = media.currentTime; + // Handle backwards time (loop/seek) + if (now < lastEmitTime) { + lastEmitTime = now; + } + if (now - lastEmitTime >= intervalSec) { + lastEmitTime = now; + this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); + } + }; + media.onplay = () => { + this.isPlaying = true; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + playing: this.isPlaying, + }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); + }; + media.onpause = () => { + this.isPlaying = false; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + playing: this.isPlaying, + }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); + }; + media.onseeked = () => { + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); + }; + media.onended = () => { + lastEmitTime = 0; + mediaSessionController.updatePlaybackState(this); + }; + media.onloadeddata = () => { + this.loaded = true; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + isLoaded: this.loaded, + }); + mediaSessionController.updatePositionState(this); + }; + return media; + } +} +//# sourceMappingURL=AudioPlayer.web.js.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioPlayer.web.js.map b/packages/expo-audio/build/AudioPlayer.web.js.map new file mode 100644 index 00000000000000..35ae2f8b20652d --- /dev/null +++ b/packages/expo-audio/build/AudioPlayer.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioPlayer.web.js","sourceRoot":"","sources":["../src/AudioPlayer.web.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AudioMetadata,\n AudioPlayerOptions,\n AudioSource,\n AudioStatus,\n PitchCorrectionQuality,\n} from './Audio.types';\nimport { AudioLockScreenOptions } from './AudioConstants';\nimport { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE } from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents } from './AudioModule.types';\nimport { getAudioContext, getSourceUri, getStatusFromMedia, nextId } from './AudioUtils.web';\nimport { mediaSessionController } from './MediaSessionController.web';\n\nexport class AudioPlayerWeb\n extends globalThis.expo.SharedObject\n implements AudioPlayer\n{\n constructor(source: AudioSource, options: AudioPlayerOptions = {}) {\n super();\n const { updateInterval = 500, crossOrigin } = options;\n this.src = source;\n this.interval = Math.max(updateInterval, 1);\n this.crossOrigin = crossOrigin;\n this.media = this._createMediaElement();\n }\n\n id: number = nextId();\n isAudioSamplingSupported = false;\n isBuffering = false;\n shouldCorrectPitch = false;\n\n private src: AudioSource = null;\n private media: HTMLAudioElement;\n private interval = 500;\n private isPlaying = false;\n private loaded = false;\n private crossOrigin?: 'anonymous' | 'use-credentials';\n private analyser: AnalyserNode | null = null;\n private sourceNode: MediaElementAudioSourceNode | null = null;\n private samplingFrameId: number | null = null;\n private samplingEnabled = false;\n\n get playing(): boolean {\n return this.isPlaying;\n }\n\n get muted(): boolean {\n return this.media.muted;\n }\n\n set muted(value: boolean) {\n this.media.muted = value;\n }\n\n get loop(): boolean {\n return this.media.loop;\n }\n\n set loop(value: boolean) {\n this.media.loop = value;\n }\n\n get duration(): number {\n return this.media.duration;\n }\n\n get currentTime(): number {\n return this.media.currentTime;\n }\n\n get paused(): boolean {\n return this.media.paused;\n }\n\n get isLoaded(): boolean {\n return this.loaded;\n }\n\n get playbackRate(): number {\n return this.media.playbackRate;\n }\n\n set playbackRate(value: number) {\n this.media.playbackRate = value;\n }\n\n get volume(): number {\n return this.media.volume;\n }\n\n set volume(value: number) {\n this.media.volume = value;\n }\n\n get currentStatus(): AudioStatus {\n return getStatusFromMedia(this.media, this.id);\n }\n\n play(): void {\n this.media.play();\n this.isPlaying = true;\n }\n\n pause(): void {\n this.media.pause();\n this.isPlaying = false;\n }\n\n replace(source: AudioSource): void {\n const wasPlaying = this.isPlaying;\n const wasSampling = this.samplingEnabled;\n const mediaSessionState = mediaSessionController.getActiveState(this);\n\n // we need to remove the current media element and create a new one\n this.remove();\n\n this.src = source;\n this.isPlaying = false;\n this.loaded = false;\n this.media = this._createMediaElement();\n\n if (wasSampling) {\n this.setAudioSamplingEnabled(true);\n }\n\n if (mediaSessionState) {\n mediaSessionController.setActivePlayer(\n this,\n mediaSessionState.metadata ?? undefined,\n mediaSessionState.options ?? undefined\n );\n }\n\n // Resume playback if it was playing before\n if (wasPlaying) {\n this.play();\n }\n }\n\n async seekTo(\n seconds: number,\n toleranceMillisBefore?: number,\n toleranceMillisAfter?: number\n ): Promise {\n this.media.currentTime = seconds;\n }\n\n setAudioSamplingEnabled(enabled: boolean): void {\n if (enabled) {\n if (!this.media.crossOrigin && this._isCrossOrigin()) {\n this.isAudioSamplingSupported = false;\n return;\n }\n\n if (this.analyser) {\n return;\n }\n\n const ctx = getAudioContext();\n if (ctx.state === 'suspended') {\n ctx.resume();\n }\n\n if (!this.sourceNode) {\n this.sourceNode = ctx.createMediaElementSource(this.media);\n }\n\n this.analyser = ctx.createAnalyser();\n this.analyser.fftSize = 2048;\n\n this.sourceNode.disconnect();\n this.sourceNode.connect(this.analyser);\n this.analyser.connect(ctx.destination);\n\n const buffer = new Float32Array(this.analyser.frequencyBinCount);\n\n const sampleLoop = () => {\n if (!this.analyser) {\n return;\n }\n if (this.isPlaying) {\n this.analyser.getFloatTimeDomainData(buffer);\n this.emit(AUDIO_SAMPLE_UPDATE, {\n channels: [{ frames: Array.from(buffer) }],\n timestamp: this.media.currentTime,\n });\n }\n this.samplingFrameId = requestAnimationFrame(sampleLoop);\n };\n this.samplingFrameId = requestAnimationFrame(sampleLoop);\n\n this.samplingEnabled = true;\n this.isAudioSamplingSupported = true;\n } else {\n if (this.samplingFrameId != null) {\n cancelAnimationFrame(this.samplingFrameId);\n this.samplingFrameId = null;\n }\n\n if (this.analyser) {\n this.analyser.disconnect();\n this.analyser = null;\n }\n\n if (this.sourceNode) {\n const ctx = getAudioContext();\n this.sourceNode.disconnect();\n this.sourceNode.connect(ctx.destination);\n }\n\n this.samplingEnabled = false;\n }\n }\n\n setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void {\n this.media.playbackRate = second;\n this.shouldCorrectPitch = pitchCorrectionQuality === 'high';\n this.media.preservesPitch = this.shouldCorrectPitch;\n mediaSessionController.updatePositionState(this);\n }\n\n remove(): void {\n mediaSessionController.clear(this);\n\n if (this.samplingFrameId != null) {\n cancelAnimationFrame(this.samplingFrameId);\n this.samplingFrameId = null;\n }\n\n if (this.analyser) {\n this.analyser.disconnect();\n this.analyser = null;\n }\n\n if (this.sourceNode) {\n this.sourceNode.disconnect();\n this.sourceNode = null;\n }\n\n this.samplingEnabled = false;\n this.media.pause();\n this.media.removeAttribute('src');\n this.media.load();\n getStatusFromMedia(this.media, this.id);\n }\n\n setActiveForLockScreen(\n active: boolean,\n metadata?: AudioMetadata,\n options?: AudioLockScreenOptions\n ): void {\n if (active) {\n mediaSessionController.setActivePlayer(this, metadata, options);\n } else {\n mediaSessionController.clear(this);\n }\n }\n\n updateLockScreenMetadata(metadata: AudioMetadata): void {\n mediaSessionController.updateMetadata(this, metadata);\n }\n\n clearLockScreenControls(): void {\n mediaSessionController.clear(this);\n }\n\n _isCrossOrigin(): boolean {\n try {\n return new URL(this.media.src).origin !== window.location.origin;\n } catch {\n return false;\n }\n }\n\n _createMediaElement(): HTMLAudioElement {\n const newSource = getSourceUri(this.src);\n const media = new Audio(newSource);\n if (this.crossOrigin !== undefined) {\n media.crossOrigin = this.crossOrigin;\n }\n\n let lastEmitTime = 0;\n const intervalSec = this.interval / 1000;\n\n // Throttled status updates based on interval\n media.ontimeupdate = () => {\n const now = media.currentTime;\n // Handle backwards time (loop/seek)\n if (now < lastEmitTime) {\n lastEmitTime = now;\n }\n if (now - lastEmitTime >= intervalSec) {\n lastEmitTime = now;\n this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id));\n mediaSessionController.updatePositionState(this);\n }\n };\n\n media.onplay = () => {\n this.isPlaying = true;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n playing: this.isPlaying,\n });\n mediaSessionController.updatePlaybackState(this);\n mediaSessionController.updatePositionState(this);\n };\n\n media.onpause = () => {\n this.isPlaying = false;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n playing: this.isPlaying,\n });\n mediaSessionController.updatePlaybackState(this);\n mediaSessionController.updatePositionState(this);\n };\n\n media.onseeked = () => {\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id));\n mediaSessionController.updatePositionState(this);\n };\n\n media.onended = () => {\n lastEmitTime = 0;\n mediaSessionController.updatePlaybackState(this);\n };\n\n media.onloadeddata = () => {\n this.loaded = true;\n lastEmitTime = media.currentTime;\n this.emit(PLAYBACK_STATUS_UPDATE, {\n ...getStatusFromMedia(media, this.id),\n isLoaded: this.loaded,\n });\n mediaSessionController.updatePositionState(this);\n };\n\n return media;\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioRecorder.web.d.ts b/packages/expo-audio/build/AudioRecorder.web.d.ts new file mode 100644 index 00000000000000..94ef0c817c56e7 --- /dev/null +++ b/packages/expo-audio/build/AudioRecorder.web.d.ts @@ -0,0 +1,40 @@ +import { RecorderState, RecordingInput, RecordingOptions, RecordingStartOptions } from './Audio.types'; +import { AudioRecorder, RecordingEvents } from './AudioModule.types'; +export declare class AudioRecorderWeb extends globalThis.expo.SharedObject implements AudioRecorder { + constructor(options: Partial); + setup(): Promise; + id: number; + currentTime: number; + uri: string | null; + private options; + private mediaRecorder; + private mediaRecorderUptimeOfLastStartResume; + private mediaRecorderIsRecording; + private timeoutIds; + private cachedInputs; + private selectedDeviceId; + private stream; + private handleDeviceChange; + private analyser; + private analyserBuffer; + private analyserSource; + private meteringEnabled; + get isRecording(): boolean; + record(options?: RecordingStartOptions): void; + private startActualRecording; + getAvailableInputs(): RecordingInput[]; + getCurrentInput(): Promise; + prepareToRecordAsync(): Promise; + getStatus(): RecorderState; + pause(): void; + recordForDuration(seconds: number): void; + setInput(input: string): void; + startRecordingAtTime(seconds: number): void; + stop(): Promise; + clearTimeouts(): void; + private createMediaRecorder; + private updateCachedInputs; + private getMeteringLevel; + private getAudioRecorderDurationMillis; +} +//# sourceMappingURL=AudioRecorder.web.d.ts.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioRecorder.web.d.ts.map b/packages/expo-audio/build/AudioRecorder.web.d.ts.map new file mode 100644 index 00000000000000..24edd8aea3b4b1 --- /dev/null +++ b/packages/expo-audio/build/AudioRecorder.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioRecorder.web.d.ts","sourceRoot":"","sources":["../src/AudioRecorder.web.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,gBAAgB,EAEhB,qBAAqB,EACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAIrE,qBAAa,gBACX,SAAQ,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,eAAe,CACpD,YAAW,aAAa;gBAEZ,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAKxC,KAAK;IAIX,EAAE,SAAY;IACd,WAAW,SAAK;IAChB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1B,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,oCAAoC,CAAK;IACjD,OAAO,CAAC,wBAAwB,CAAS;IACzC,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,YAAY,CAAwB;IAC5C,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,QAAQ,CAA6B;IAC7C,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,cAAc,CAA2C;IACjE,OAAO,CAAC,eAAe,CAAS;IAEhC,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,MAAM,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,IAAI;IAyB7C,OAAO,CAAC,oBAAoB;IAQ5B,kBAAkB,IAAI,cAAc,EAAE;IAItC,eAAe,IAAI,OAAO,CAAC,cAAc,CAAC;IAgBpC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C,SAAS,IAAI,aAAa;IAe1B,KAAK,IAAI,IAAI;IAUb,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIxC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAO7B,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIrC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B,aAAa;YAIC,mBAAmB;YAiGnB,kBAAkB;IAahC,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,8BAA8B;CAOvC"} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioRecorder.web.js b/packages/expo-audio/build/AudioRecorder.web.js new file mode 100644 index 00000000000000..c9c460a4dd17dd --- /dev/null +++ b/packages/expo-audio/build/AudioRecorder.web.js @@ -0,0 +1,239 @@ +import { RECORDING_STATUS_UPDATE } from './AudioEventKeys'; +import { getAudioContext, getUserMedia, nextId } from './AudioUtils.web'; +import { RecordingPresets } from './RecordingConstants'; +export class AudioRecorderWeb extends globalThis.expo.SharedObject { + constructor(options) { + super(); + this.options = options; + } + async setup() { + this.mediaRecorder = await this.createMediaRecorder(this.options); + } + id = nextId(); + currentTime = 0; + uri = null; + options; + mediaRecorder = null; + mediaRecorderUptimeOfLastStartResume = 0; + mediaRecorderIsRecording = false; + timeoutIds = []; + cachedInputs = []; + selectedDeviceId = null; + stream = null; + handleDeviceChange = null; + analyser = null; + analyserBuffer = null; + analyserSource = null; + meteringEnabled = false; + get isRecording() { + return this.mediaRecorder?.state === 'recording'; + } + record(options) { + if (this.mediaRecorder === null) { + throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); + } + // Clear any existing timeouts + this.clearTimeouts(); + // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely + // Only forDuration is implemented using setTimeout + const { forDuration } = options || {}; + this.startActualRecording(); + if (forDuration !== undefined) { + this.timeoutIds.push(setTimeout(() => { + this.stop(); + }, forDuration * 1000)); + } + } + startActualRecording() { + if (this.mediaRecorder?.state === 'paused') { + this.mediaRecorder.resume(); + } + else { + this.mediaRecorder?.start(); + } + } + getAvailableInputs() { + return this.cachedInputs; + } + getCurrentInput() { + const deviceId = this.selectedDeviceId ?? this.stream?.getAudioTracks()[0]?.getSettings().deviceId; + const matched = this.cachedInputs.find((input) => input.uid === deviceId); + if (matched) { + return Promise.resolve(matched); + } + return Promise.resolve(this.cachedInputs[0] ?? { + type: 'Default', + name: 'Default', + uid: 'Default', + }); + } + async prepareToRecordAsync() { + return this.setup(); + } + getStatus() { + const status = { + canRecord: this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive', + isRecording: this.mediaRecorder?.state === 'recording', + durationMillis: this.getAudioRecorderDurationMillis(), + mediaServicesDidReset: false, + url: this.uri, + }; + if (this.meteringEnabled && this.mediaRecorderIsRecording) { + status.metering = this.getMeteringLevel(); + } + return status; + } + pause() { + if (this.mediaRecorder === null) { + throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); + } + this.mediaRecorder?.pause(); + } + recordForDuration(seconds) { + this.record({ forDuration: seconds }); + } + setInput(input) { + if (!this.cachedInputs.some((cached) => cached.uid === input)) { + throw new Error(`No audio input device found for uid: ${input}`); + } + this.selectedDeviceId = input; + } + startRecordingAtTime(seconds) { + this.record({ atTime: seconds }); + } + async stop() { + if (this.mediaRecorder === null) { + throw new Error('Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'); + } + const dataPromise = new Promise((resolve) => this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data))); + this.mediaRecorder?.stop(); + this.mediaRecorder = null; + const data = await dataPromise; + const url = URL.createObjectURL(data); + this.uri = url; + this.emit(RECORDING_STATUS_UPDATE, { + id: this.id, + isFinished: true, + hasError: false, + error: null, + url, + }); + } + clearTimeouts() { + this.timeoutIds.forEach((id) => clearTimeout(id)); + } + async createMediaRecorder(options) { + if (typeof navigator !== 'undefined' && !navigator.mediaDevices) { + throw new Error('No media devices available'); + } + this.mediaRecorderUptimeOfLastStartResume = 0; + this.currentTime = 0; + const audioConstraints = this.selectedDeviceId + ? { deviceId: { exact: this.selectedDeviceId } } + : true; + const stream = await getUserMedia({ audio: audioConstraints }); + this.stream = stream; + await this.updateCachedInputs(); + this.handleDeviceChange = () => { + this.updateCachedInputs(); + }; + navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange); + if (options.isMeteringEnabled) { + const ctx = getAudioContext(); + if (ctx.state === 'suspended') { + ctx.resume(); + } + this.analyserSource = ctx.createMediaStreamSource(stream); + this.analyser = ctx.createAnalyser(); + this.analyser.fftSize = 2048; + this.analyserSource.connect(this.analyser); + this.analyserBuffer = new Float32Array(this.analyser.frequencyBinCount); + this.meteringEnabled = true; + } + const defaults = RecordingPresets.HIGH_QUALITY.web; + const mediaRecorderOptions = {}; + const mimeType = options.mimeType ?? defaults.mimeType; + if (mimeType && MediaRecorder.isTypeSupported(mimeType)) { + mediaRecorderOptions.mimeType = mimeType; + } + if (options.bitsPerSecond) { + mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond; + } + else if (options.bitRate) { + mediaRecorderOptions.audioBitsPerSecond = options.bitRate; + } + else { + mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond; + } + const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions); + mediaRecorder.addEventListener('pause', () => { + this.currentTime = this.getAudioRecorderDurationMillis(); + this.mediaRecorderIsRecording = false; + }); + mediaRecorder.addEventListener('resume', () => { + this.mediaRecorderUptimeOfLastStartResume = Date.now(); + this.mediaRecorderIsRecording = true; + }); + mediaRecorder.addEventListener('start', () => { + this.mediaRecorderUptimeOfLastStartResume = Date.now(); + this.currentTime = 0; + this.mediaRecorderIsRecording = true; + }); + mediaRecorder?.addEventListener('stop', () => { + this.currentTime = 0; + this.mediaRecorderIsRecording = false; + this.stream = null; + if (this.analyserSource) { + this.analyserSource.disconnect(); + this.analyserSource = null; + } + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + this.analyserBuffer = null; + } + if (this.handleDeviceChange) { + navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange); + this.handleDeviceChange = null; + } + // Clears recording icon in Chrome tab + stream.getTracks().forEach((track) => track.stop()); + }); + return mediaRecorder; + } + async updateCachedInputs() { + const devices = await navigator.mediaDevices.enumerateDevices(); + this.cachedInputs = devices + .filter((device) => device.kind === 'audioinput') + .map((device) => ({ + uid: device.deviceId, + name: device.label || 'Unknown Device', + type: device.deviceId === 'default' ? 'Default' : 'Unknown', + })); + } + // Compute the metering level in dBFS using the same RMS-to-decibel formula as + // native (20 * log10(rms)). -160 represents silence / no signal. + getMeteringLevel() { + if (!this.analyser || !this.analyserBuffer) { + return -160; + } + this.analyser.getFloatTimeDomainData(this.analyserBuffer); + let sumSquares = 0; + for (let i = 0; i < this.analyserBuffer.length; i++) { + sumSquares += this.analyserBuffer[i] * this.analyserBuffer[i]; + } + const rms = Math.sqrt(sumSquares / this.analyserBuffer.length); + if (rms === 0) { + return -160; + } + return 20 * Math.log10(rms); + } + getAudioRecorderDurationMillis() { + let duration = this.currentTime; + if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { + duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume; + } + return duration; + } +} +//# sourceMappingURL=AudioRecorder.web.js.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioRecorder.web.js.map b/packages/expo-audio/build/AudioRecorder.web.js.map new file mode 100644 index 00000000000000..1523e9d9309502 --- /dev/null +++ b/packages/expo-audio/build/AudioRecorder.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioRecorder.web.js","sourceRoot":"","sources":["../src/AudioRecorder.web.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n RecorderState,\n RecordingInput,\n RecordingOptions,\n RecordingOptionsWeb,\n RecordingStartOptions,\n} from './Audio.types';\nimport { RECORDING_STATUS_UPDATE } from './AudioEventKeys';\nimport { AudioRecorder, RecordingEvents } from './AudioModule.types';\nimport { getAudioContext, getUserMedia, nextId } from './AudioUtils.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nexport class AudioRecorderWeb\n extends globalThis.expo.SharedObject\n implements AudioRecorder\n{\n constructor(options: Partial) {\n super();\n this.options = options;\n }\n\n async setup() {\n this.mediaRecorder = await this.createMediaRecorder(this.options);\n }\n\n id = nextId();\n currentTime = 0;\n uri: string | null = null;\n\n private options: Partial;\n private mediaRecorder: MediaRecorder | null = null;\n private mediaRecorderUptimeOfLastStartResume = 0;\n private mediaRecorderIsRecording = false;\n private timeoutIds: number[] = [];\n private cachedInputs: RecordingInput[] = [];\n private selectedDeviceId: string | null = null;\n private stream: MediaStream | null = null;\n private handleDeviceChange: (() => void) | null = null;\n private analyser: AnalyserNode | null = null;\n private analyserBuffer: Float32Array | null = null;\n private analyserSource: MediaStreamAudioSourceNode | null = null;\n private meteringEnabled = false;\n\n get isRecording(): boolean {\n return this.mediaRecorder?.state === 'recording';\n }\n\n record(options?: RecordingStartOptions): void {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n // Clear any existing timeouts\n this.clearTimeouts();\n\n // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely\n // Only forDuration is implemented using setTimeout\n const { forDuration } = options || {};\n\n this.startActualRecording();\n\n if (forDuration !== undefined) {\n this.timeoutIds.push(\n setTimeout(() => {\n this.stop();\n }, forDuration * 1000)\n );\n }\n }\n\n private startActualRecording(): void {\n if (this.mediaRecorder?.state === 'paused') {\n this.mediaRecorder.resume();\n } else {\n this.mediaRecorder?.start();\n }\n }\n\n getAvailableInputs(): RecordingInput[] {\n return this.cachedInputs;\n }\n\n getCurrentInput(): Promise {\n const deviceId =\n this.selectedDeviceId ?? this.stream?.getAudioTracks()[0]?.getSettings().deviceId;\n const matched = this.cachedInputs.find((input) => input.uid === deviceId);\n if (matched) {\n return Promise.resolve(matched);\n }\n return Promise.resolve(\n this.cachedInputs[0] ?? {\n type: 'Default',\n name: 'Default',\n uid: 'Default',\n }\n );\n }\n\n async prepareToRecordAsync(): Promise {\n return this.setup();\n }\n\n getStatus(): RecorderState {\n const status: RecorderState = {\n canRecord:\n this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive',\n isRecording: this.mediaRecorder?.state === 'recording',\n durationMillis: this.getAudioRecorderDurationMillis(),\n mediaServicesDidReset: false,\n url: this.uri,\n };\n if (this.meteringEnabled && this.mediaRecorderIsRecording) {\n status.metering = this.getMeteringLevel();\n }\n return status;\n }\n\n pause(): void {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n this.mediaRecorder?.pause();\n }\n\n recordForDuration(seconds: number): void {\n this.record({ forDuration: seconds });\n }\n\n setInput(input: string): void {\n if (!this.cachedInputs.some((cached) => cached.uid === input)) {\n throw new Error(`No audio input device found for uid: ${input}`);\n }\n this.selectedDeviceId = input;\n }\n\n startRecordingAtTime(seconds: number): void {\n this.record({ atTime: seconds });\n }\n\n async stop(): Promise {\n if (this.mediaRecorder === null) {\n throw new Error(\n 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.'\n );\n }\n\n const dataPromise = new Promise((resolve) =>\n this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data))\n );\n\n this.mediaRecorder?.stop();\n this.mediaRecorder = null;\n\n const data = await dataPromise;\n const url = URL.createObjectURL(data);\n\n this.uri = url;\n\n this.emit(RECORDING_STATUS_UPDATE, {\n id: this.id,\n isFinished: true,\n hasError: false,\n error: null,\n url,\n });\n }\n\n clearTimeouts() {\n this.timeoutIds.forEach((id) => clearTimeout(id));\n }\n\n private async createMediaRecorder(\n options: Partial & Partial\n ): Promise {\n if (typeof navigator !== 'undefined' && !navigator.mediaDevices) {\n throw new Error('No media devices available');\n }\n\n this.mediaRecorderUptimeOfLastStartResume = 0;\n this.currentTime = 0;\n\n const audioConstraints = this.selectedDeviceId\n ? { deviceId: { exact: this.selectedDeviceId } }\n : true;\n const stream = await getUserMedia({ audio: audioConstraints });\n this.stream = stream;\n\n await this.updateCachedInputs();\n\n this.handleDeviceChange = () => {\n this.updateCachedInputs();\n };\n navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange);\n\n if (options.isMeteringEnabled) {\n const ctx = getAudioContext();\n if (ctx.state === 'suspended') {\n ctx.resume();\n }\n this.analyserSource = ctx.createMediaStreamSource(stream);\n this.analyser = ctx.createAnalyser();\n this.analyser.fftSize = 2048;\n this.analyserSource.connect(this.analyser);\n this.analyserBuffer = new Float32Array(this.analyser.frequencyBinCount);\n this.meteringEnabled = true;\n }\n\n const defaults = RecordingPresets.HIGH_QUALITY.web;\n const mediaRecorderOptions: MediaRecorderOptions = {};\n\n const mimeType = options.mimeType ?? defaults.mimeType;\n if (mimeType && MediaRecorder.isTypeSupported(mimeType)) {\n mediaRecorderOptions.mimeType = mimeType;\n }\n\n if (options.bitsPerSecond) {\n mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond;\n } else if (options.bitRate) {\n mediaRecorderOptions.audioBitsPerSecond = options.bitRate;\n } else {\n mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond;\n }\n\n const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions);\n\n mediaRecorder.addEventListener('pause', () => {\n this.currentTime = this.getAudioRecorderDurationMillis();\n this.mediaRecorderIsRecording = false;\n });\n\n mediaRecorder.addEventListener('resume', () => {\n this.mediaRecorderUptimeOfLastStartResume = Date.now();\n this.mediaRecorderIsRecording = true;\n });\n\n mediaRecorder.addEventListener('start', () => {\n this.mediaRecorderUptimeOfLastStartResume = Date.now();\n this.currentTime = 0;\n this.mediaRecorderIsRecording = true;\n });\n\n mediaRecorder?.addEventListener('stop', () => {\n this.currentTime = 0;\n this.mediaRecorderIsRecording = false;\n this.stream = null;\n\n if (this.analyserSource) {\n this.analyserSource.disconnect();\n this.analyserSource = null;\n }\n if (this.analyser) {\n this.analyser.disconnect();\n this.analyser = null;\n this.analyserBuffer = null;\n }\n\n if (this.handleDeviceChange) {\n navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange);\n this.handleDeviceChange = null;\n }\n\n // Clears recording icon in Chrome tab\n stream.getTracks().forEach((track) => track.stop());\n });\n\n return mediaRecorder;\n }\n\n private async updateCachedInputs() {\n const devices = await navigator.mediaDevices.enumerateDevices();\n this.cachedInputs = devices\n .filter((device) => device.kind === 'audioinput')\n .map((device) => ({\n uid: device.deviceId,\n name: device.label || 'Unknown Device',\n type: device.deviceId === 'default' ? 'Default' : 'Unknown',\n }));\n }\n\n // Compute the metering level in dBFS using the same RMS-to-decibel formula as\n // native (20 * log10(rms)). -160 represents silence / no signal.\n private getMeteringLevel(): number {\n if (!this.analyser || !this.analyserBuffer) {\n return -160;\n }\n this.analyser.getFloatTimeDomainData(this.analyserBuffer);\n let sumSquares = 0;\n for (let i = 0; i < this.analyserBuffer.length; i++) {\n sumSquares += this.analyserBuffer[i] * this.analyserBuffer[i];\n }\n const rms = Math.sqrt(sumSquares / this.analyserBuffer.length);\n if (rms === 0) {\n return -160;\n }\n return 20 * Math.log10(rms);\n }\n\n private getAudioRecorderDurationMillis() {\n let duration = this.currentTime;\n if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) {\n duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume;\n }\n return duration;\n }\n}\n"]} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioUtils.web.d.ts b/packages/expo-audio/build/AudioUtils.web.d.ts new file mode 100644 index 00000000000000..cc86bedab56fdf --- /dev/null +++ b/packages/expo-audio/build/AudioUtils.web.d.ts @@ -0,0 +1,7 @@ +import { AudioSource, AudioStatus } from './Audio.types'; +export declare const nextId: () => number; +export declare function getAudioContext(): AudioContext; +export declare function getUserMedia(constraints: MediaStreamConstraints): Promise; +export declare function getStatusFromMedia(media: HTMLMediaElement, id: number): AudioStatus; +export declare function getSourceUri(source: AudioSource): string | undefined; +//# sourceMappingURL=AudioUtils.web.d.ts.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioUtils.web.d.ts.map b/packages/expo-audio/build/AudioUtils.web.d.ts.map new file mode 100644 index 00000000000000..536d6bfdaa1674 --- /dev/null +++ b/packages/expo-audio/build/AudioUtils.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioUtils.web.d.ts","sourceRoot":"","sources":["../src/AudioUtils.web.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEzD,eAAO,MAAM,MAAM,cAGf,CAAC;AAIL,wBAAgB,eAAe,IAAI,YAAY,CAK9C;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CA4BtF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CA0BnF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAcpE"} \ No newline at end of file diff --git a/packages/expo-audio/build/AudioUtils.web.js b/packages/expo-audio/build/AudioUtils.web.js new file mode 100644 index 00000000000000..0ebfed9d630b7e --- /dev/null +++ b/packages/expo-audio/build/AudioUtils.web.js @@ -0,0 +1,76 @@ +import { Asset } from 'expo-asset'; +export const nextId = (() => { + let id = 0; + return () => id++; +})(); +let audioContext = null; +export function getAudioContext() { + if (!audioContext) { + audioContext = new AudioContext(); + } + return audioContext; +} +export function getUserMedia(constraints) { + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + return navigator.mediaDevices.getUserMedia(constraints); + } + // Some browsers partially implement mediaDevices. We can't just assign an object + // with getUserMedia as it would overwrite existing properties. + // Here, we will just add the getUserMedia property if it's missing. + // First get ahold of the legacy getUserMedia, if present + const getUserMedia = + // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia + navigator.getUserMedia || + navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || + function () { + const error = new Error('Permission unimplemented'); + error.code = 0; + error.name = 'NotAllowedError'; + throw error; + }; + return new Promise((resolve, reject) => { + // TODO(@kitten): The types indicates that this is incorrect. + // Please check whether this is correct! + // @ts-expect-error: The `successCallback` doesn't match a `resolve` function + getUserMedia.call(navigator, constraints, resolve, reject); + }); +} +export function getStatusFromMedia(media, id) { + const isPlaying = !!(media.currentTime > 0 && + !media.paused && + !media.ended && + media.readyState > 2); + const status = { + id, + isLoaded: true, + duration: media.duration, + currentTime: media.currentTime, + playbackState: '', + timeControlStatus: isPlaying ? 'playing' : 'paused', + reasonForWaitingToPlay: '', + playing: isPlaying, + didJustFinish: media.ended, + isBuffering: false, + playbackRate: media.playbackRate, + shouldCorrectPitch: true, + mute: media.muted, + loop: media.loop, + }; + return status; +} +export function getSourceUri(source) { + if (typeof source === 'string') { + return source; + } + if (typeof source === 'number') { + const asset = Asset.fromModule(source); + return asset.uri; + } + if (typeof source?.assetId === 'number' && !source?.uri) { + const asset = Asset.fromModule(source.assetId); + return asset.uri; + } + return source?.uri ?? undefined; +} +//# sourceMappingURL=AudioUtils.web.js.map \ No newline at end of file diff --git a/packages/expo-audio/build/AudioUtils.web.js.map b/packages/expo-audio/build/AudioUtils.web.js.map new file mode 100644 index 00000000000000..75fe0843994db3 --- /dev/null +++ b/packages/expo-audio/build/AudioUtils.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"AudioUtils.web.js","sourceRoot":"","sources":["../src/AudioUtils.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;IAC1B,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,OAAO,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;AACpB,CAAC,CAAC,EAAE,CAAC;AAEL,IAAI,YAAY,GAAwB,IAAI,CAAC;AAE7C,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,WAAmC;IAC9D,IAAI,SAAS,CAAC,YAAY,IAAI,SAAS,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;QAClE,OAAO,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IAC1D,CAAC;IAED,iFAAiF;IACjF,+DAA+D;IAC/D,oEAAoE;IAEpE,yDAAyD;IACzD,MAAM,YAAY;IAChB,yHAAyH;IACzH,SAAS,CAAC,YAAY;QACtB,SAAS,CAAC,kBAAkB;QAC5B,SAAS,CAAC,eAAe;QACzB;YACE,MAAM,KAAK,GAAQ,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YACzD,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;YACf,KAAK,CAAC,IAAI,GAAG,iBAAiB,CAAC;YAC/B,MAAM,KAAK,CAAC;QACd,CAAC,CAAC;IAEJ,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,6DAA6D;QAC7D,wCAAwC;QACxC,6EAA6E;QAC7E,YAAY,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAuB,EAAE,EAAU;IACpE,MAAM,SAAS,GAAG,CAAC,CAAC,CAClB,KAAK,CAAC,WAAW,GAAG,CAAC;QACrB,CAAC,KAAK,CAAC,MAAM;QACb,CAAC,KAAK,CAAC,KAAK;QACZ,KAAK,CAAC,UAAU,GAAG,CAAC,CACrB,CAAC;IAEF,MAAM,MAAM,GAAgB;QAC1B,EAAE;QACF,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,aAAa,EAAE,EAAE;QACjB,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;QACnD,sBAAsB,EAAE,EAAE;QAC1B,OAAO,EAAE,SAAS;QAClB,aAAa,EAAE,KAAK,CAAC,KAAK;QAC1B,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,kBAAkB,EAAE,IAAI;QACxB,IAAI,EAAE,KAAK,CAAC,KAAK;QACjB,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QACvC,OAAO,KAAK,CAAC,GAAG,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,MAAM,EAAE,OAAO,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,GAAG,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,EAAE,GAAG,IAAI,SAAS,CAAC;AAClC,CAAC","sourcesContent":["import { Asset } from 'expo-asset';\n\nimport { AudioSource, AudioStatus } from './Audio.types';\n\nexport const nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nexport function getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\n}\n\nexport function getUserMedia(constraints: MediaStreamConstraints): Promise {\n if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {\n return navigator.mediaDevices.getUserMedia(constraints);\n }\n\n // Some browsers partially implement mediaDevices. We can't just assign an object\n // with getUserMedia as it would overwrite existing properties.\n // Here, we will just add the getUserMedia property if it's missing.\n\n // First get ahold of the legacy getUserMedia, if present\n const getUserMedia =\n // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia\n navigator.getUserMedia ||\n navigator.webkitGetUserMedia ||\n navigator.mozGetUserMedia ||\n function () {\n const error: any = new Error('Permission unimplemented');\n error.code = 0;\n error.name = 'NotAllowedError';\n throw error;\n };\n\n return new Promise((resolve, reject) => {\n // TODO(@kitten): The types indicates that this is incorrect.\n // Please check whether this is correct!\n // @ts-expect-error: The `successCallback` doesn't match a `resolve` function\n getUserMedia.call(navigator, constraints, resolve, reject);\n });\n}\n\nexport function getStatusFromMedia(media: HTMLMediaElement, id: number): AudioStatus {\n const isPlaying = !!(\n media.currentTime > 0 &&\n !media.paused &&\n !media.ended &&\n media.readyState > 2\n );\n\n const status: AudioStatus = {\n id,\n isLoaded: true,\n duration: media.duration,\n currentTime: media.currentTime,\n playbackState: '',\n timeControlStatus: isPlaying ? 'playing' : 'paused',\n reasonForWaitingToPlay: '',\n playing: isPlaying,\n didJustFinish: media.ended,\n isBuffering: false,\n playbackRate: media.playbackRate,\n shouldCorrectPitch: true,\n mute: media.muted,\n loop: media.loop,\n };\n\n return status;\n}\n\nexport function getSourceUri(source: AudioSource): string | undefined {\n if (typeof source === 'string') {\n return source;\n }\n if (typeof source === 'number') {\n const asset = Asset.fromModule(source);\n return asset.uri;\n }\n if (typeof source?.assetId === 'number' && !source?.uri) {\n const asset = Asset.fromModule(source.assetId);\n return asset.uri;\n }\n\n return source?.uri ?? undefined;\n}\n"]} \ No newline at end of file diff --git a/packages/expo-audio/build/MediaSessionController.web.d.ts b/packages/expo-audio/build/MediaSessionController.web.d.ts new file mode 100644 index 00000000000000..a0fd90b1ee1966 --- /dev/null +++ b/packages/expo-audio/build/MediaSessionController.web.d.ts @@ -0,0 +1,32 @@ +import { AudioMetadata } from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; +interface MediaSessionPlayer { + play(): void; + pause(): void; + seekTo(seconds: number): Promise; + readonly playing: boolean; + readonly currentTime: number; + readonly duration: number; + readonly playbackRate: number; +} +declare class MediaSessionController { + private activePlayer; + private metadata; + private options; + setActivePlayer(player: MediaSessionPlayer, metadata?: AudioMetadata, options?: AudioLockScreenOptions): void; + updateMetadata(player: MediaSessionPlayer, metadata: AudioMetadata): void; + clear(player: MediaSessionPlayer): void; + updatePlaybackState(player: MediaSessionPlayer): void; + updatePositionState(player: MediaSessionPlayer): void; + isActive(player: MediaSessionPlayer): boolean; + getActiveState(player: MediaSessionPlayer): { + metadata: AudioMetadata | null; + options: AudioLockScreenOptions | null; + } | null; + private _applyMetadata; + private _setHandler; + private _applyActionHandlers; +} +export declare const mediaSessionController: MediaSessionController; +export {}; +//# sourceMappingURL=MediaSessionController.web.d.ts.map \ No newline at end of file diff --git a/packages/expo-audio/build/MediaSessionController.web.d.ts.map b/packages/expo-audio/build/MediaSessionController.web.d.ts.map new file mode 100644 index 00000000000000..290c3c5474edc3 --- /dev/null +++ b/packages/expo-audio/build/MediaSessionController.web.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"MediaSessionController.web.d.ts","sourceRoot":"","sources":["../src/MediaSessionController.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAID,cAAM,sBAAsB;IAC1B,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,OAAO,CAAuC;IAEtD,eAAe,CACb,MAAM,EAAE,kBAAkB,EAC1B,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI;IAiBP,cAAc,CAAC,MAAM,EAAE,kBAAkB,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAQzE,KAAK,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IA6BvC,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAOrD,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAoBrD,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO;IAI7C,cAAc,CACZ,MAAM,EAAE,kBAAkB,GACzB;QAAE,QAAQ,EAAE,aAAa,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAKpF,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,oBAAoB;CAiD7B;AAED,eAAO,MAAM,sBAAsB,wBAA+B,CAAC"} \ No newline at end of file diff --git a/packages/expo-audio/build/MediaSessionController.web.js b/packages/expo-audio/build/MediaSessionController.web.js new file mode 100644 index 00000000000000..c541f15092e1a1 --- /dev/null +++ b/packages/expo-audio/build/MediaSessionController.web.js @@ -0,0 +1,156 @@ +const SKIP_SECONDS = 10; +class MediaSessionController { + activePlayer = null; + metadata = null; + options = null; + setActivePlayer(player, metadata, options) { + if (!navigator.mediaSession) + return; + if (this.activePlayer && this.activePlayer !== player) { + this.clear(this.activePlayer); + } + this.activePlayer = player; + this.metadata = metadata ?? null; + this.options = options ?? null; + this._applyMetadata(); + this._applyActionHandlers(); + this.updatePlaybackState(player); + this.updatePositionState(player); + } + updateMetadata(player, metadata) { + if (!navigator.mediaSession) + return; + if (this.activePlayer !== player) + return; + this.metadata = metadata; + this._applyMetadata(); + } + clear(player) { + if (!navigator.mediaSession) + return; + if (this.activePlayer !== player) + return; + this.activePlayer = null; + this.metadata = null; + this.options = null; + navigator.mediaSession.metadata = null; + navigator.mediaSession.playbackState = 'none'; + const actions = [ + 'play', + 'pause', + 'seekto', + 'seekforward', + 'seekbackward', + 'previoustrack', + 'nexttrack', + ]; + for (const action of actions) { + this._setHandler(action, null); + } + try { + navigator.mediaSession.setPositionState(); + } + catch { } + } + updatePlaybackState(player) { + if (!navigator.mediaSession) + return; + if (this.activePlayer !== player) + return; + navigator.mediaSession.playbackState = player.playing ? 'playing' : 'paused'; + } + updatePositionState(player) { + if (!navigator.mediaSession) + return; + if (this.activePlayer !== player) + return; + const duration = player.duration; + if (!Number.isFinite(duration) || duration <= 0) + return; + const position = Math.min(Math.max(player.currentTime, 0), duration); + const playbackRate = player.playbackRate || 1; + try { + navigator.mediaSession.setPositionState({ + duration, + playbackRate, + position, + }); + } + catch { } + } + isActive(player) { + return this.activePlayer === player; + } + getActiveState(player) { + if (this.activePlayer !== player) + return null; + return { metadata: this.metadata, options: this.options }; + } + _applyMetadata() { + if (!this.metadata) { + navigator.mediaSession.metadata = null; + return; + } + const { title, artist, albumTitle, artworkUrl } = this.metadata; + const artwork = artworkUrl ? [{ src: artworkUrl }] : []; + navigator.mediaSession.metadata = new MediaMetadata({ + title: title ?? '', + artist: artist ?? '', + album: albumTitle ?? '', + artwork, + }); + } + _setHandler(action, handler) { + try { + navigator.mediaSession.setActionHandler(action, handler); + } + catch { } + } + _applyActionHandlers() { + const player = this.activePlayer; + if (!player) + return; + this._setHandler('play', () => { + player.play(); + }); + this._setHandler('pause', () => { + player.pause(); + }); + this._setHandler('seekto', (details) => { + if (details.seekTime != null) { + player.seekTo(details.seekTime); + this.updatePositionState(player); + } + }); + const seekForward = (details) => { + const skipTime = details.seekOffset ?? SKIP_SECONDS; + const newTime = Math.min(player.currentTime + skipTime, player.duration || 0); + player.seekTo(newTime); + this.updatePositionState(player); + }; + const seekBackward = (details) => { + const skipTime = details.seekOffset ?? SKIP_SECONDS; + const newTime = Math.max(player.currentTime - skipTime, 0); + player.seekTo(newTime); + this.updatePositionState(player); + }; + if (this.options?.showSeekForward === true) { + this._setHandler('seekforward', seekForward); + this._setHandler('nexttrack', seekForward); + } + else { + this._setHandler('seekforward', null); + this._setHandler('nexttrack', null); + } + if (this.options?.showSeekBackward === true) { + this._setHandler('seekbackward', seekBackward); + this._setHandler('previoustrack', seekBackward); + } + else { + this._setHandler('seekbackward', null); + this._setHandler('previoustrack', null); + } + } +} +export const mediaSessionController = new MediaSessionController(); +//# sourceMappingURL=MediaSessionController.web.js.map \ No newline at end of file diff --git a/packages/expo-audio/build/MediaSessionController.web.js.map b/packages/expo-audio/build/MediaSessionController.web.js.map new file mode 100644 index 00000000000000..6f9b9b894400d8 --- /dev/null +++ b/packages/expo-audio/build/MediaSessionController.web.js.map @@ -0,0 +1 @@ +{"version":3,"file":"MediaSessionController.web.js","sourceRoot":"","sources":["../src/MediaSessionController.web.ts"],"names":[],"mappings":"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","sourcesContent":["import { AudioMetadata } from './Audio.types';\nimport { AudioLockScreenOptions } from './AudioConstants';\n\ninterface MediaSessionPlayer {\n play(): void;\n pause(): void;\n seekTo(seconds: number): Promise;\n readonly playing: boolean;\n readonly currentTime: number;\n readonly duration: number;\n readonly playbackRate: number;\n}\n\nconst SKIP_SECONDS = 10;\n\nclass MediaSessionController {\n private activePlayer: MediaSessionPlayer | null = null;\n private metadata: AudioMetadata | null = null;\n private options: AudioLockScreenOptions | null = null;\n\n setActivePlayer(\n player: MediaSessionPlayer,\n metadata?: AudioMetadata,\n options?: AudioLockScreenOptions\n ): void {\n if (!navigator.mediaSession) return;\n\n if (this.activePlayer && this.activePlayer !== player) {\n this.clear(this.activePlayer);\n }\n\n this.activePlayer = player;\n this.metadata = metadata ?? null;\n this.options = options ?? null;\n\n this._applyMetadata();\n this._applyActionHandlers();\n this.updatePlaybackState(player);\n this.updatePositionState(player);\n }\n\n updateMetadata(player: MediaSessionPlayer, metadata: AudioMetadata): void {\n if (!navigator.mediaSession) return;\n if (this.activePlayer !== player) return;\n\n this.metadata = metadata;\n this._applyMetadata();\n }\n\n clear(player: MediaSessionPlayer): void {\n if (!navigator.mediaSession) return;\n if (this.activePlayer !== player) return;\n\n this.activePlayer = null;\n this.metadata = null;\n this.options = null;\n\n navigator.mediaSession.metadata = null;\n navigator.mediaSession.playbackState = 'none';\n\n const actions: MediaSessionAction[] = [\n 'play',\n 'pause',\n 'seekto',\n 'seekforward',\n 'seekbackward',\n 'previoustrack',\n 'nexttrack',\n ];\n for (const action of actions) {\n this._setHandler(action, null);\n }\n\n try {\n navigator.mediaSession.setPositionState();\n } catch {}\n }\n\n updatePlaybackState(player: MediaSessionPlayer): void {\n if (!navigator.mediaSession) return;\n if (this.activePlayer !== player) return;\n\n navigator.mediaSession.playbackState = player.playing ? 'playing' : 'paused';\n }\n\n updatePositionState(player: MediaSessionPlayer): void {\n if (!navigator.mediaSession) return;\n if (this.activePlayer !== player) return;\n\n const duration = player.duration;\n\n if (!Number.isFinite(duration) || duration <= 0) return;\n\n const position = Math.min(Math.max(player.currentTime, 0), duration);\n const playbackRate = player.playbackRate || 1;\n\n try {\n navigator.mediaSession.setPositionState({\n duration,\n playbackRate,\n position,\n });\n } catch {}\n }\n\n isActive(player: MediaSessionPlayer): boolean {\n return this.activePlayer === player;\n }\n\n getActiveState(\n player: MediaSessionPlayer\n ): { metadata: AudioMetadata | null; options: AudioLockScreenOptions | null } | null {\n if (this.activePlayer !== player) return null;\n return { metadata: this.metadata, options: this.options };\n }\n\n private _applyMetadata(): void {\n if (!this.metadata) {\n navigator.mediaSession.metadata = null;\n return;\n }\n\n const { title, artist, albumTitle, artworkUrl } = this.metadata;\n const artwork: MediaImage[] = artworkUrl ? [{ src: artworkUrl }] : [];\n\n navigator.mediaSession.metadata = new MediaMetadata({\n title: title ?? '',\n artist: artist ?? '',\n album: albumTitle ?? '',\n artwork,\n });\n }\n\n private _setHandler(action: MediaSessionAction, handler: MediaSessionActionHandler | null): void {\n try {\n navigator.mediaSession.setActionHandler(action, handler);\n } catch {}\n }\n\n private _applyActionHandlers(): void {\n const player = this.activePlayer;\n if (!player) return;\n\n this._setHandler('play', () => {\n player.play();\n });\n\n this._setHandler('pause', () => {\n player.pause();\n });\n\n this._setHandler('seekto', (details) => {\n if (details.seekTime != null) {\n player.seekTo(details.seekTime);\n this.updatePositionState(player);\n }\n });\n\n const seekForward = (details: MediaSessionActionDetails) => {\n const skipTime = details.seekOffset ?? SKIP_SECONDS;\n const newTime = Math.min(player.currentTime + skipTime, player.duration || 0);\n player.seekTo(newTime);\n this.updatePositionState(player);\n };\n\n const seekBackward = (details: MediaSessionActionDetails) => {\n const skipTime = details.seekOffset ?? SKIP_SECONDS;\n const newTime = Math.max(player.currentTime - skipTime, 0);\n player.seekTo(newTime);\n this.updatePositionState(player);\n };\n\n if (this.options?.showSeekForward === true) {\n this._setHandler('seekforward', seekForward);\n this._setHandler('nexttrack', seekForward);\n } else {\n this._setHandler('seekforward', null);\n this._setHandler('nexttrack', null);\n }\n\n if (this.options?.showSeekBackward === true) {\n this._setHandler('seekbackward', seekBackward);\n this._setHandler('previoustrack', seekBackward);\n } else {\n this._setHandler('seekbackward', null);\n this._setHandler('previoustrack', null);\n }\n }\n}\n\nexport const mediaSessionController = new MediaSessionController();\n"]} \ No newline at end of file diff --git a/packages/expo-audio/src/AudioModule.web.ts b/packages/expo-audio/src/AudioModule.web.ts index b18c25cb1ebc64..eb6538521ace0a 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -1,26 +1,10 @@ -import { Asset } from 'expo-asset'; import { PermissionResponse, PermissionStatus } from 'expo-modules-core'; -import { - AudioMode, - AudioPlayerOptions, - AudioSource, - AudioStatus, - PitchCorrectionQuality, - RecorderState, - RecordingInput, - RecordingOptions, - RecordingOptionsWeb, - RecordingStartOptions, -} from './Audio.types'; -import { PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE } from './AudioEventKeys'; -import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; -import { RecordingPresets } from './RecordingConstants'; +import { AudioMode } from './Audio.types'; +import { getUserMedia } from './AudioUtils.web'; -const nextId = (() => { - let id = 0; - return () => id++; -})(); +export { AudioPlayerWeb } from './AudioPlayer.web'; +export { AudioRecorderWeb } from './AudioRecorder.web'; async function getPermissionWithQueryAsync( name: PermissionNameWithAdditionalValues @@ -43,486 +27,6 @@ async function getPermissionWithQueryAsync( } } -function getUserMedia(constraints: MediaStreamConstraints): Promise { - if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { - return navigator.mediaDevices.getUserMedia(constraints); - } - - // Some browsers partially implement mediaDevices. We can't just assign an object - // with getUserMedia as it would overwrite existing properties. - // Here, we will just add the getUserMedia property if it's missing. - - // First get ahold of the legacy getUserMedia, if present - const getUserMedia = - // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia - navigator.getUserMedia || - navigator.webkitGetUserMedia || - navigator.mozGetUserMedia || - function () { - const error: any = new Error('Permission unimplemented'); - error.code = 0; - error.name = 'NotAllowedError'; - throw error; - }; - - return new Promise((resolve, reject) => { - // TODO(@kitten): The types indicates that this is incorrect. - // Please check whether this is correct! - // @ts-expect-error: The `successCallback` doesn't match a `resolve` function - getUserMedia.call(navigator, constraints, resolve, reject); - }); -} - -function getStatusFromMedia(media: HTMLMediaElement, id: number): AudioStatus { - const isPlaying = !!( - media.currentTime > 0 && - !media.paused && - !media.ended && - media.readyState > 2 - ); - - const status: AudioStatus = { - id, - isLoaded: true, - duration: media.duration, - currentTime: media.currentTime, - playbackState: '', - timeControlStatus: isPlaying ? 'playing' : 'paused', - reasonForWaitingToPlay: '', - playing: isPlaying, - didJustFinish: media.ended, - isBuffering: false, - playbackRate: media.playbackRate, - shouldCorrectPitch: true, - mute: media.muted, - loop: media.loop, - }; - - return status; -} - -export class AudioPlayerWeb - extends globalThis.expo.SharedObject - implements AudioPlayer -{ - constructor(source: AudioSource, options: AudioPlayerOptions = {}) { - super(); - const { updateInterval = 500, crossOrigin } = options; - this.src = source; - this.interval = Math.max(updateInterval, 1); - this.crossOrigin = crossOrigin; - this.media = this._createMediaElement(); - } - - id: number = nextId(); - isAudioSamplingSupported = false; - isBuffering = false; - shouldCorrectPitch = false; - - private src: AudioSource = null; - private media: HTMLAudioElement; - private interval = 500; - private isPlaying = false; - private loaded = false; - private crossOrigin?: 'anonymous' | 'use-credentials'; - - get playing(): boolean { - return this.isPlaying; - } - - get muted(): boolean { - return this.media.muted; - } - - set muted(value: boolean) { - this.media.muted = value; - } - - get loop(): boolean { - return this.media.loop; - } - - set loop(value: boolean) { - this.media.loop = value; - } - - get duration(): number { - return this.media.duration; - } - - get currentTime(): number { - return this.media.currentTime; - } - - get paused(): boolean { - return this.media.paused; - } - - get isLoaded(): boolean { - return this.loaded; - } - - get playbackRate(): number { - return this.media.playbackRate; - } - - set playbackRate(value: number) { - this.media.playbackRate = value; - } - - get volume(): number { - return this.media.volume; - } - - set volume(value: number) { - this.media.volume = value; - } - - get currentStatus(): AudioStatus { - return getStatusFromMedia(this.media, this.id); - } - - play(): void { - this.media.play(); - this.isPlaying = true; - } - - pause(): void { - this.media.pause(); - this.isPlaying = false; - } - - replace(source: AudioSource): void { - const wasPlaying = this.isPlaying; - - // we need to remove the current media element and create a new one - this.remove(); - - this.src = source; - this.isPlaying = false; - this.loaded = false; - this.media = this._createMediaElement(); - - // Resume playback if it was playing before - if (wasPlaying) { - this.play(); - } - } - - async seekTo( - seconds: number, - toleranceMillisBefore?: number, - toleranceMillisAfter?: number - ): Promise { - this.media.currentTime = seconds; - } - - // Not supported on web - setAudioSamplingEnabled(enabled: boolean): void { - this.isAudioSamplingSupported = false; - } - - setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void { - this.media.playbackRate = second; - this.shouldCorrectPitch = pitchCorrectionQuality === 'high'; - this.media.preservesPitch = this.shouldCorrectPitch; - } - - remove(): void { - this.media.pause(); - this.media.removeAttribute('src'); - this.media.load(); - getStatusFromMedia(this.media, this.id); - } - - setActiveForLockScreen(active: boolean, metadata: Record): void {} - updateLockScreenMetadata(metadata: Record): void {} - clearLockScreenControls(): void {} - - _createMediaElement(): HTMLAudioElement { - const newSource = getSourceUri(this.src); - const media = new Audio(newSource); - if (this.crossOrigin !== undefined) { - media.crossOrigin = this.crossOrigin; - } - - let lastEmitTime = 0; - const intervalSec = this.interval / 1000; - - // Throttled status updates based on interval - media.ontimeupdate = () => { - const now = media.currentTime; - // Handle backwards time (loop/seek) - if (now < lastEmitTime) { - lastEmitTime = now; - } - if (now - lastEmitTime >= intervalSec) { - lastEmitTime = now; - this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); - } - }; - - media.onplay = () => { - this.isPlaying = true; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - playing: this.isPlaying, - }); - }; - - media.onpause = () => { - this.isPlaying = false; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - playing: this.isPlaying, - }); - }; - - media.onseeked = () => { - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); - }; - - media.onended = () => { - lastEmitTime = 0; - }; - - media.onloadeddata = () => { - this.loaded = true; - lastEmitTime = media.currentTime; - this.emit(PLAYBACK_STATUS_UPDATE, { - ...getStatusFromMedia(media, this.id), - isLoaded: this.loaded, - }); - }; - - return media; - } -} - -function getSourceUri(source: AudioSource): string | undefined { - if (typeof source === 'string') { - return source; - } - if (typeof source === 'number') { - const asset = Asset.fromModule(source); - return asset.uri; - } - if (typeof source?.assetId === 'number' && !source?.uri) { - const asset = Asset.fromModule(source.assetId); - return asset.uri; - } - - return source?.uri ?? undefined; -} - -export class AudioRecorderWeb - extends globalThis.expo.SharedObject - implements AudioRecorder -{ - constructor(options: Partial) { - super(); - this.options = options; - } - - async setup() { - this.mediaRecorder = await this.createMediaRecorder(this.options); - } - - id = nextId(); - currentTime = 0; - uri: string | null = null; - - private options: Partial; - private mediaRecorder: MediaRecorder | null = null; - private mediaRecorderUptimeOfLastStartResume = 0; - private mediaRecorderIsRecording = false; - private timeoutIds: number[] = []; - - get isRecording(): boolean { - return this.mediaRecorder?.state === 'recording'; - } - - record(options?: RecordingStartOptions): void { - if (this.mediaRecorder === null) { - throw new Error( - 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' - ); - } - - // Clear any existing timeouts - this.clearTimeouts(); - - // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely - // Only forDuration is implemented using setTimeout - const { forDuration } = options || {}; - - this.startActualRecording(); - - if (forDuration !== undefined) { - this.timeoutIds.push( - setTimeout(() => { - this.stop(); - }, forDuration * 1000) - ); - } - } - - private startActualRecording(): void { - if (this.mediaRecorder?.state === 'paused') { - this.mediaRecorder.resume(); - } else { - this.mediaRecorder?.start(); - } - } - - getAvailableInputs(): RecordingInput[] { - return []; - } - - getCurrentInput(): Promise { - return Promise.resolve({ - type: 'Default', - name: 'Default', - uid: 'Default', - }); - } - - async prepareToRecordAsync(): Promise { - return this.setup(); - } - - getStatus(): RecorderState { - return { - canRecord: - this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive', - isRecording: this.mediaRecorder?.state === 'recording', - durationMillis: this.getAudioRecorderDurationMillis(), - mediaServicesDidReset: false, - url: this.uri, - }; - } - - pause(): void { - if (this.mediaRecorder === null) { - throw new Error( - 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' - ); - } - - this.mediaRecorder?.pause(); - } - - recordForDuration(seconds: number): void { - this.record({ forDuration: seconds }); - } - - setInput(input: string): void {} - - startRecordingAtTime(seconds: number): void { - this.record({ atTime: seconds }); - } - - async stop(): Promise { - if (this.mediaRecorder === null) { - throw new Error( - 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' - ); - } - - const dataPromise = new Promise((resolve) => - this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data)) - ); - - this.mediaRecorder?.stop(); - this.mediaRecorder = null; - - const data = await dataPromise; - const url = URL.createObjectURL(data); - - this.uri = url; - - this.emit(RECORDING_STATUS_UPDATE, { - id: this.id, - isFinished: true, - hasError: false, - error: null, - url, - }); - } - - clearTimeouts() { - this.timeoutIds.forEach((id) => clearTimeout(id)); - } - - private async createMediaRecorder( - options: Partial & Partial - ): Promise { - if (typeof navigator !== 'undefined' && !navigator.mediaDevices) { - throw new Error('No media devices available'); - } - - this.mediaRecorderUptimeOfLastStartResume = 0; - this.currentTime = 0; - - const stream = await getUserMedia({ audio: true }); - - const defaults = RecordingPresets.HIGH_QUALITY.web; - const mediaRecorderOptions: MediaRecorderOptions = {}; - - const mimeType = options.mimeType ?? defaults.mimeType; - if (mimeType && MediaRecorder.isTypeSupported(mimeType)) { - mediaRecorderOptions.mimeType = mimeType; - } - - if (options.bitsPerSecond) { - mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond; - } else if (options.bitRate) { - mediaRecorderOptions.audioBitsPerSecond = options.bitRate; - } else { - mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond; - } - - const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions); - - mediaRecorder.addEventListener('pause', () => { - this.currentTime = this.getAudioRecorderDurationMillis(); - this.mediaRecorderIsRecording = false; - }); - - mediaRecorder.addEventListener('resume', () => { - this.mediaRecorderUptimeOfLastStartResume = Date.now(); - this.mediaRecorderIsRecording = true; - }); - - mediaRecorder.addEventListener('start', () => { - this.mediaRecorderUptimeOfLastStartResume = Date.now(); - this.currentTime = 0; - this.mediaRecorderIsRecording = true; - }); - - mediaRecorder?.addEventListener('stop', () => { - this.currentTime = 0; - this.mediaRecorderIsRecording = false; - - // Clears recording icon in Chrome tab - stream.getTracks().forEach((track) => track.stop()); - }); - - return mediaRecorder; - } - - private getAudioRecorderDurationMillis() { - let duration = this.currentTime; - if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { - duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume; - } - return duration; - } -} - export async function setAudioModeAsync(mode: AudioMode) {} export async function setIsAudioActiveAsync(active: boolean) {} diff --git a/packages/expo-audio/src/AudioPlayer.web.ts b/packages/expo-audio/src/AudioPlayer.web.ts new file mode 100644 index 00000000000000..eb4a0400d142ab --- /dev/null +++ b/packages/expo-audio/src/AudioPlayer.web.ts @@ -0,0 +1,344 @@ +import { + AudioMetadata, + AudioPlayerOptions, + AudioSource, + AudioStatus, + PitchCorrectionQuality, +} from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; +import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE } from './AudioEventKeys'; +import { AudioPlayer, AudioEvents } from './AudioModule.types'; +import { getAudioContext, getSourceUri, getStatusFromMedia, nextId } from './AudioUtils.web'; +import { mediaSessionController } from './MediaSessionController.web'; + +export class AudioPlayerWeb + extends globalThis.expo.SharedObject + implements AudioPlayer +{ + constructor(source: AudioSource, options: AudioPlayerOptions = {}) { + super(); + const { updateInterval = 500, crossOrigin } = options; + this.src = source; + this.interval = Math.max(updateInterval, 1); + this.crossOrigin = crossOrigin; + this.media = this._createMediaElement(); + } + + id: number = nextId(); + isAudioSamplingSupported = false; + isBuffering = false; + shouldCorrectPitch = false; + + private src: AudioSource = null; + private media: HTMLAudioElement; + private interval = 500; + private isPlaying = false; + private loaded = false; + private crossOrigin?: 'anonymous' | 'use-credentials'; + private analyser: AnalyserNode | null = null; + private sourceNode: MediaElementAudioSourceNode | null = null; + private samplingFrameId: number | null = null; + private samplingEnabled = false; + + get playing(): boolean { + return this.isPlaying; + } + + get muted(): boolean { + return this.media.muted; + } + + set muted(value: boolean) { + this.media.muted = value; + } + + get loop(): boolean { + return this.media.loop; + } + + set loop(value: boolean) { + this.media.loop = value; + } + + get duration(): number { + return this.media.duration; + } + + get currentTime(): number { + return this.media.currentTime; + } + + get paused(): boolean { + return this.media.paused; + } + + get isLoaded(): boolean { + return this.loaded; + } + + get playbackRate(): number { + return this.media.playbackRate; + } + + set playbackRate(value: number) { + this.media.playbackRate = value; + } + + get volume(): number { + return this.media.volume; + } + + set volume(value: number) { + this.media.volume = value; + } + + get currentStatus(): AudioStatus { + return getStatusFromMedia(this.media, this.id); + } + + play(): void { + this.media.play(); + this.isPlaying = true; + } + + pause(): void { + this.media.pause(); + this.isPlaying = false; + } + + replace(source: AudioSource): void { + const wasPlaying = this.isPlaying; + const wasSampling = this.samplingEnabled; + const mediaSessionState = mediaSessionController.getActiveState(this); + + // we need to remove the current media element and create a new one + this.remove(); + + this.src = source; + this.isPlaying = false; + this.loaded = false; + this.media = this._createMediaElement(); + + if (wasSampling) { + this.setAudioSamplingEnabled(true); + } + + if (mediaSessionState) { + mediaSessionController.setActivePlayer( + this, + mediaSessionState.metadata ?? undefined, + mediaSessionState.options ?? undefined + ); + } + + // Resume playback if it was playing before + if (wasPlaying) { + this.play(); + } + } + + async seekTo( + seconds: number, + toleranceMillisBefore?: number, + toleranceMillisAfter?: number + ): Promise { + this.media.currentTime = seconds; + } + + setAudioSamplingEnabled(enabled: boolean): void { + if (enabled) { + if (!this.media.crossOrigin && this._isCrossOrigin()) { + this.isAudioSamplingSupported = false; + return; + } + + if (this.analyser) { + return; + } + + const ctx = getAudioContext(); + if (ctx.state === 'suspended') { + ctx.resume(); + } + + if (!this.sourceNode) { + this.sourceNode = ctx.createMediaElementSource(this.media); + } + + this.analyser = ctx.createAnalyser(); + this.analyser.fftSize = 2048; + + this.sourceNode.disconnect(); + this.sourceNode.connect(this.analyser); + this.analyser.connect(ctx.destination); + + const buffer = new Float32Array(this.analyser.frequencyBinCount); + + const sampleLoop = () => { + if (!this.analyser) { + return; + } + if (this.isPlaying) { + this.analyser.getFloatTimeDomainData(buffer); + this.emit(AUDIO_SAMPLE_UPDATE, { + channels: [{ frames: Array.from(buffer) }], + timestamp: this.media.currentTime, + }); + } + this.samplingFrameId = requestAnimationFrame(sampleLoop); + }; + this.samplingFrameId = requestAnimationFrame(sampleLoop); + + this.samplingEnabled = true; + this.isAudioSamplingSupported = true; + } else { + if (this.samplingFrameId != null) { + cancelAnimationFrame(this.samplingFrameId); + this.samplingFrameId = null; + } + + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + } + + if (this.sourceNode) { + const ctx = getAudioContext(); + this.sourceNode.disconnect(); + this.sourceNode.connect(ctx.destination); + } + + this.samplingEnabled = false; + } + } + + setPlaybackRate(second: number, pitchCorrectionQuality?: PitchCorrectionQuality): void { + this.media.playbackRate = second; + this.shouldCorrectPitch = pitchCorrectionQuality === 'high'; + this.media.preservesPitch = this.shouldCorrectPitch; + mediaSessionController.updatePositionState(this); + } + + remove(): void { + mediaSessionController.clear(this); + + if (this.samplingFrameId != null) { + cancelAnimationFrame(this.samplingFrameId); + this.samplingFrameId = null; + } + + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + } + + if (this.sourceNode) { + this.sourceNode.disconnect(); + this.sourceNode = null; + } + + this.samplingEnabled = false; + this.media.pause(); + this.media.removeAttribute('src'); + this.media.load(); + getStatusFromMedia(this.media, this.id); + } + + setActiveForLockScreen( + active: boolean, + metadata?: AudioMetadata, + options?: AudioLockScreenOptions + ): void { + if (active) { + mediaSessionController.setActivePlayer(this, metadata, options); + } else { + mediaSessionController.clear(this); + } + } + + updateLockScreenMetadata(metadata: AudioMetadata): void { + mediaSessionController.updateMetadata(this, metadata); + } + + clearLockScreenControls(): void { + mediaSessionController.clear(this); + } + + _isCrossOrigin(): boolean { + try { + return new URL(this.media.src).origin !== window.location.origin; + } catch { + return false; + } + } + + _createMediaElement(): HTMLAudioElement { + const newSource = getSourceUri(this.src); + const media = new Audio(newSource); + if (this.crossOrigin !== undefined) { + media.crossOrigin = this.crossOrigin; + } + + let lastEmitTime = 0; + const intervalSec = this.interval / 1000; + + // Throttled status updates based on interval + media.ontimeupdate = () => { + const now = media.currentTime; + // Handle backwards time (loop/seek) + if (now < lastEmitTime) { + lastEmitTime = now; + } + if (now - lastEmitTime >= intervalSec) { + lastEmitTime = now; + this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); + } + }; + + media.onplay = () => { + this.isPlaying = true; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + playing: this.isPlaying, + }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); + }; + + media.onpause = () => { + this.isPlaying = false; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + playing: this.isPlaying, + }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); + }; + + media.onseeked = () => { + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); + }; + + media.onended = () => { + lastEmitTime = 0; + mediaSessionController.updatePlaybackState(this); + }; + + media.onloadeddata = () => { + this.loaded = true; + lastEmitTime = media.currentTime; + this.emit(PLAYBACK_STATUS_UPDATE, { + ...getStatusFromMedia(media, this.id), + isLoaded: this.loaded, + }); + mediaSessionController.updatePositionState(this); + }; + + return media; + } +} diff --git a/packages/expo-audio/src/AudioRecorder.web.ts b/packages/expo-audio/src/AudioRecorder.web.ts new file mode 100644 index 00000000000000..0cf69e118d92bd --- /dev/null +++ b/packages/expo-audio/src/AudioRecorder.web.ts @@ -0,0 +1,310 @@ +import { + RecorderState, + RecordingInput, + RecordingOptions, + RecordingOptionsWeb, + RecordingStartOptions, +} from './Audio.types'; +import { RECORDING_STATUS_UPDATE } from './AudioEventKeys'; +import { AudioRecorder, RecordingEvents } from './AudioModule.types'; +import { getAudioContext, getUserMedia, nextId } from './AudioUtils.web'; +import { RecordingPresets } from './RecordingConstants'; + +export class AudioRecorderWeb + extends globalThis.expo.SharedObject + implements AudioRecorder +{ + constructor(options: Partial) { + super(); + this.options = options; + } + + async setup() { + this.mediaRecorder = await this.createMediaRecorder(this.options); + } + + id = nextId(); + currentTime = 0; + uri: string | null = null; + + private options: Partial; + private mediaRecorder: MediaRecorder | null = null; + private mediaRecorderUptimeOfLastStartResume = 0; + private mediaRecorderIsRecording = false; + private timeoutIds: number[] = []; + private cachedInputs: RecordingInput[] = []; + private selectedDeviceId: string | null = null; + private stream: MediaStream | null = null; + private handleDeviceChange: (() => void) | null = null; + private analyser: AnalyserNode | null = null; + private analyserBuffer: Float32Array | null = null; + private analyserSource: MediaStreamAudioSourceNode | null = null; + private meteringEnabled = false; + + get isRecording(): boolean { + return this.mediaRecorder?.state === 'recording'; + } + + record(options?: RecordingStartOptions): void { + if (this.mediaRecorder === null) { + throw new Error( + 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' + ); + } + + // Clear any existing timeouts + this.clearTimeouts(); + + // Note: atTime is not supported on Web (no native equivalent), so we ignore it entirely + // Only forDuration is implemented using setTimeout + const { forDuration } = options || {}; + + this.startActualRecording(); + + if (forDuration !== undefined) { + this.timeoutIds.push( + setTimeout(() => { + this.stop(); + }, forDuration * 1000) + ); + } + } + + private startActualRecording(): void { + if (this.mediaRecorder?.state === 'paused') { + this.mediaRecorder.resume(); + } else { + this.mediaRecorder?.start(); + } + } + + getAvailableInputs(): RecordingInput[] { + return this.cachedInputs; + } + + getCurrentInput(): Promise { + const deviceId = + this.selectedDeviceId ?? this.stream?.getAudioTracks()[0]?.getSettings().deviceId; + const matched = this.cachedInputs.find((input) => input.uid === deviceId); + if (matched) { + return Promise.resolve(matched); + } + return Promise.resolve( + this.cachedInputs[0] ?? { + type: 'Default', + name: 'Default', + uid: 'Default', + } + ); + } + + async prepareToRecordAsync(): Promise { + return this.setup(); + } + + getStatus(): RecorderState { + const status: RecorderState = { + canRecord: + this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive', + isRecording: this.mediaRecorder?.state === 'recording', + durationMillis: this.getAudioRecorderDurationMillis(), + mediaServicesDidReset: false, + url: this.uri, + }; + if (this.meteringEnabled && this.mediaRecorderIsRecording) { + status.metering = this.getMeteringLevel(); + } + return status; + } + + pause(): void { + if (this.mediaRecorder === null) { + throw new Error( + 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' + ); + } + + this.mediaRecorder?.pause(); + } + + recordForDuration(seconds: number): void { + this.record({ forDuration: seconds }); + } + + setInput(input: string): void { + if (!this.cachedInputs.some((cached) => cached.uid === input)) { + throw new Error(`No audio input device found for uid: ${input}`); + } + this.selectedDeviceId = input; + } + + startRecordingAtTime(seconds: number): void { + this.record({ atTime: seconds }); + } + + async stop(): Promise { + if (this.mediaRecorder === null) { + throw new Error( + 'Cannot start an audio recording without initializing a MediaRecorder. Run prepareToRecordAsync() before attempting to start an audio recording.' + ); + } + + const dataPromise = new Promise((resolve) => + this.mediaRecorder?.addEventListener('dataavailable', (e) => resolve(e.data)) + ); + + this.mediaRecorder?.stop(); + this.mediaRecorder = null; + + const data = await dataPromise; + const url = URL.createObjectURL(data); + + this.uri = url; + + this.emit(RECORDING_STATUS_UPDATE, { + id: this.id, + isFinished: true, + hasError: false, + error: null, + url, + }); + } + + clearTimeouts() { + this.timeoutIds.forEach((id) => clearTimeout(id)); + } + + private async createMediaRecorder( + options: Partial & Partial + ): Promise { + if (typeof navigator !== 'undefined' && !navigator.mediaDevices) { + throw new Error('No media devices available'); + } + + this.mediaRecorderUptimeOfLastStartResume = 0; + this.currentTime = 0; + + const audioConstraints = this.selectedDeviceId + ? { deviceId: { exact: this.selectedDeviceId } } + : true; + const stream = await getUserMedia({ audio: audioConstraints }); + this.stream = stream; + + await this.updateCachedInputs(); + + this.handleDeviceChange = () => { + this.updateCachedInputs(); + }; + navigator.mediaDevices.addEventListener('devicechange', this.handleDeviceChange); + + if (options.isMeteringEnabled) { + const ctx = getAudioContext(); + if (ctx.state === 'suspended') { + ctx.resume(); + } + this.analyserSource = ctx.createMediaStreamSource(stream); + this.analyser = ctx.createAnalyser(); + this.analyser.fftSize = 2048; + this.analyserSource.connect(this.analyser); + this.analyserBuffer = new Float32Array(this.analyser.frequencyBinCount); + this.meteringEnabled = true; + } + + const defaults = RecordingPresets.HIGH_QUALITY.web; + const mediaRecorderOptions: MediaRecorderOptions = {}; + + const mimeType = options.mimeType ?? defaults.mimeType; + if (mimeType && MediaRecorder.isTypeSupported(mimeType)) { + mediaRecorderOptions.mimeType = mimeType; + } + + if (options.bitsPerSecond) { + mediaRecorderOptions.bitsPerSecond = options.bitsPerSecond; + } else if (options.bitRate) { + mediaRecorderOptions.audioBitsPerSecond = options.bitRate; + } else { + mediaRecorderOptions.bitsPerSecond = defaults.bitsPerSecond; + } + + const mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions); + + mediaRecorder.addEventListener('pause', () => { + this.currentTime = this.getAudioRecorderDurationMillis(); + this.mediaRecorderIsRecording = false; + }); + + mediaRecorder.addEventListener('resume', () => { + this.mediaRecorderUptimeOfLastStartResume = Date.now(); + this.mediaRecorderIsRecording = true; + }); + + mediaRecorder.addEventListener('start', () => { + this.mediaRecorderUptimeOfLastStartResume = Date.now(); + this.currentTime = 0; + this.mediaRecorderIsRecording = true; + }); + + mediaRecorder?.addEventListener('stop', () => { + this.currentTime = 0; + this.mediaRecorderIsRecording = false; + this.stream = null; + + if (this.analyserSource) { + this.analyserSource.disconnect(); + this.analyserSource = null; + } + if (this.analyser) { + this.analyser.disconnect(); + this.analyser = null; + this.analyserBuffer = null; + } + + if (this.handleDeviceChange) { + navigator.mediaDevices?.removeEventListener('devicechange', this.handleDeviceChange); + this.handleDeviceChange = null; + } + + // Clears recording icon in Chrome tab + stream.getTracks().forEach((track) => track.stop()); + }); + + return mediaRecorder; + } + + private async updateCachedInputs() { + const devices = await navigator.mediaDevices.enumerateDevices(); + this.cachedInputs = devices + .filter((device) => device.kind === 'audioinput') + .map((device) => ({ + uid: device.deviceId, + name: device.label || 'Unknown Device', + type: device.deviceId === 'default' ? 'Default' : 'Unknown', + })); + } + + // Compute the metering level in dBFS using the same RMS-to-decibel formula as + // native (20 * log10(rms)). -160 represents silence / no signal. + private getMeteringLevel(): number { + if (!this.analyser || !this.analyserBuffer) { + return -160; + } + this.analyser.getFloatTimeDomainData(this.analyserBuffer); + let sumSquares = 0; + for (let i = 0; i < this.analyserBuffer.length; i++) { + sumSquares += this.analyserBuffer[i] * this.analyserBuffer[i]; + } + const rms = Math.sqrt(sumSquares / this.analyserBuffer.length); + if (rms === 0) { + return -160; + } + return 20 * Math.log10(rms); + } + + private getAudioRecorderDurationMillis() { + let duration = this.currentTime; + if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { + duration += Date.now() - this.mediaRecorderUptimeOfLastStartResume; + } + return duration; + } +} diff --git a/packages/expo-audio/src/AudioUtils.web.ts b/packages/expo-audio/src/AudioUtils.web.ts new file mode 100644 index 00000000000000..9e6bf28679ca13 --- /dev/null +++ b/packages/expo-audio/src/AudioUtils.web.ts @@ -0,0 +1,91 @@ +import { Asset } from 'expo-asset'; + +import { AudioSource, AudioStatus } from './Audio.types'; + +export const nextId = (() => { + let id = 0; + return () => id++; +})(); + +let audioContext: AudioContext | null = null; + +export function getAudioContext(): AudioContext { + if (!audioContext) { + audioContext = new AudioContext(); + } + return audioContext; +} + +export function getUserMedia(constraints: MediaStreamConstraints): Promise { + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + return navigator.mediaDevices.getUserMedia(constraints); + } + + // Some browsers partially implement mediaDevices. We can't just assign an object + // with getUserMedia as it would overwrite existing properties. + // Here, we will just add the getUserMedia property if it's missing. + + // First get ahold of the legacy getUserMedia, if present + const getUserMedia = + // TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia + navigator.getUserMedia || + navigator.webkitGetUserMedia || + navigator.mozGetUserMedia || + function () { + const error: any = new Error('Permission unimplemented'); + error.code = 0; + error.name = 'NotAllowedError'; + throw error; + }; + + return new Promise((resolve, reject) => { + // TODO(@kitten): The types indicates that this is incorrect. + // Please check whether this is correct! + // @ts-expect-error: The `successCallback` doesn't match a `resolve` function + getUserMedia.call(navigator, constraints, resolve, reject); + }); +} + +export function getStatusFromMedia(media: HTMLMediaElement, id: number): AudioStatus { + const isPlaying = !!( + media.currentTime > 0 && + !media.paused && + !media.ended && + media.readyState > 2 + ); + + const status: AudioStatus = { + id, + isLoaded: true, + duration: media.duration, + currentTime: media.currentTime, + playbackState: '', + timeControlStatus: isPlaying ? 'playing' : 'paused', + reasonForWaitingToPlay: '', + playing: isPlaying, + didJustFinish: media.ended, + isBuffering: false, + playbackRate: media.playbackRate, + shouldCorrectPitch: true, + mute: media.muted, + loop: media.loop, + }; + + return status; +} + +export function getSourceUri(source: AudioSource): string | undefined { + if (typeof source === 'string') { + return source; + } + if (typeof source === 'number') { + const asset = Asset.fromModule(source); + return asset.uri; + } + if (typeof source?.assetId === 'number' && !source?.uri) { + const asset = Asset.fromModule(source.assetId); + return asset.uri; + } + + return source?.uri ?? undefined; +} diff --git a/packages/expo-audio/src/MediaSessionController.web.ts b/packages/expo-audio/src/MediaSessionController.web.ts new file mode 100644 index 00000000000000..144eef9c32d44e --- /dev/null +++ b/packages/expo-audio/src/MediaSessionController.web.ts @@ -0,0 +1,191 @@ +import { AudioMetadata } from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; + +interface MediaSessionPlayer { + play(): void; + pause(): void; + seekTo(seconds: number): Promise; + readonly playing: boolean; + readonly currentTime: number; + readonly duration: number; + readonly playbackRate: number; +} + +const SKIP_SECONDS = 10; + +class MediaSessionController { + private activePlayer: MediaSessionPlayer | null = null; + private metadata: AudioMetadata | null = null; + private options: AudioLockScreenOptions | null = null; + + setActivePlayer( + player: MediaSessionPlayer, + metadata?: AudioMetadata, + options?: AudioLockScreenOptions + ): void { + if (!navigator.mediaSession) return; + + if (this.activePlayer && this.activePlayer !== player) { + this.clear(this.activePlayer); + } + + this.activePlayer = player; + this.metadata = metadata ?? null; + this.options = options ?? null; + + this._applyMetadata(); + this._applyActionHandlers(); + this.updatePlaybackState(player); + this.updatePositionState(player); + } + + updateMetadata(player: MediaSessionPlayer, metadata: AudioMetadata): void { + if (!navigator.mediaSession) return; + if (this.activePlayer !== player) return; + + this.metadata = metadata; + this._applyMetadata(); + } + + clear(player: MediaSessionPlayer): void { + if (!navigator.mediaSession) return; + if (this.activePlayer !== player) return; + + this.activePlayer = null; + this.metadata = null; + this.options = null; + + navigator.mediaSession.metadata = null; + navigator.mediaSession.playbackState = 'none'; + + const actions: MediaSessionAction[] = [ + 'play', + 'pause', + 'seekto', + 'seekforward', + 'seekbackward', + 'previoustrack', + 'nexttrack', + ]; + for (const action of actions) { + this._setHandler(action, null); + } + + try { + navigator.mediaSession.setPositionState(); + } catch {} + } + + updatePlaybackState(player: MediaSessionPlayer): void { + if (!navigator.mediaSession) return; + if (this.activePlayer !== player) return; + + navigator.mediaSession.playbackState = player.playing ? 'playing' : 'paused'; + } + + updatePositionState(player: MediaSessionPlayer): void { + if (!navigator.mediaSession) return; + if (this.activePlayer !== player) return; + + const duration = player.duration; + + if (!Number.isFinite(duration) || duration <= 0) return; + + const position = Math.min(Math.max(player.currentTime, 0), duration); + const playbackRate = player.playbackRate || 1; + + try { + navigator.mediaSession.setPositionState({ + duration, + playbackRate, + position, + }); + } catch {} + } + + isActive(player: MediaSessionPlayer): boolean { + return this.activePlayer === player; + } + + getActiveState( + player: MediaSessionPlayer + ): { metadata: AudioMetadata | null; options: AudioLockScreenOptions | null } | null { + if (this.activePlayer !== player) return null; + return { metadata: this.metadata, options: this.options }; + } + + private _applyMetadata(): void { + if (!this.metadata) { + navigator.mediaSession.metadata = null; + return; + } + + const { title, artist, albumTitle, artworkUrl } = this.metadata; + const artwork: MediaImage[] = artworkUrl ? [{ src: artworkUrl }] : []; + + navigator.mediaSession.metadata = new MediaMetadata({ + title: title ?? '', + artist: artist ?? '', + album: albumTitle ?? '', + artwork, + }); + } + + private _setHandler(action: MediaSessionAction, handler: MediaSessionActionHandler | null): void { + try { + navigator.mediaSession.setActionHandler(action, handler); + } catch {} + } + + private _applyActionHandlers(): void { + const player = this.activePlayer; + if (!player) return; + + this._setHandler('play', () => { + player.play(); + }); + + this._setHandler('pause', () => { + player.pause(); + }); + + this._setHandler('seekto', (details) => { + if (details.seekTime != null) { + player.seekTo(details.seekTime); + this.updatePositionState(player); + } + }); + + const seekForward = (details: MediaSessionActionDetails) => { + const skipTime = details.seekOffset ?? SKIP_SECONDS; + const newTime = Math.min(player.currentTime + skipTime, player.duration || 0); + player.seekTo(newTime); + this.updatePositionState(player); + }; + + const seekBackward = (details: MediaSessionActionDetails) => { + const skipTime = details.seekOffset ?? SKIP_SECONDS; + const newTime = Math.max(player.currentTime - skipTime, 0); + player.seekTo(newTime); + this.updatePositionState(player); + }; + + if (this.options?.showSeekForward === true) { + this._setHandler('seekforward', seekForward); + this._setHandler('nexttrack', seekForward); + } else { + this._setHandler('seekforward', null); + this._setHandler('nexttrack', null); + } + + if (this.options?.showSeekBackward === true) { + this._setHandler('seekbackward', seekBackward); + this._setHandler('previoustrack', seekBackward); + } else { + this._setHandler('seekbackward', null); + this._setHandler('previoustrack', null); + } + } +} + +export const mediaSessionController = new MediaSessionController(); diff --git a/packages/expo-dev-menu/CHANGELOG.md b/packages/expo-dev-menu/CHANGELOG.md index 4888d214cc36cf..bbadc9f57918b8 100644 --- a/packages/expo-dev-menu/CHANGELOG.md +++ b/packages/expo-dev-menu/CHANGELOG.md @@ -8,6 +8,8 @@ ### ๐Ÿ› Bug fixes +- update labels for consistency ([#42825](https://github.com/expo/expo/pull/42825) by [@vonovak](https://github.com/vonovak)) + ### ๐Ÿ’ก Others ## 55.0.5 โ€” 2026-02-08 diff --git a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/MenuIcons.kt b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/MenuIcons.kt index f49c4e15b6f823..363d547f0467cd 100644 --- a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/MenuIcons.kt +++ b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/MenuIcons.kt @@ -107,14 +107,14 @@ object MenuIcons { } @Composable - fun Bug( + fun Code( size: Dp, tint: Color, modifier: Modifier = Modifier ) { Icon( - painter = painterResource(R.drawable.bug), - contentDescription = "JS debugger", + painter = painterResource(R.drawable.code_brackets), + contentDescription = "DevTools", tint = tint, modifier = Modifier .size(size) diff --git a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/ToolsSection.kt b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/ToolsSection.kt index 48fbf44f7762ef..bbcc73e4487a92 100644 --- a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/ToolsSection.kt +++ b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/compose/ui/ToolsSection.kt @@ -38,7 +38,7 @@ fun ToolsSection( }, content = { NewText( - text = "Performance monitor" + text = "Toggle performance monitor" ) }, onClick = { @@ -58,7 +58,7 @@ fun ToolsSection( }, content = { NewText( - text = "Element inspector" + text = "Toggle element inspector" ) }, onClick = { @@ -71,14 +71,14 @@ fun ToolsSection( NewMenuButton( withSurface = false, icon = { - MenuIcons.Bug( + MenuIcons.Code( size = 20.dp, tint = NewAppTheme.colors.icon.tertiary ) }, content = { NewText( - text = "JS debugger" + text = "Open DevTools" ) }, onClick = { @@ -126,7 +126,7 @@ fun ToolsSection( }, content = { NewText( - text = "Action button" + text = "Show dev menu button" ) }, rightComponent = { diff --git a/packages/expo-dev-menu/android/src/debug/res/drawable/bug.xml b/packages/expo-dev-menu/android/src/debug/res/drawable/bug.xml deleted file mode 100644 index ce60fda6abcfff..00000000000000 --- a/packages/expo-dev-menu/android/src/debug/res/drawable/bug.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - diff --git a/packages/expo-dev-menu/android/src/debug/res/drawable/code_brackets.xml b/packages/expo-dev-menu/android/src/debug/res/drawable/code_brackets.xml new file mode 100644 index 00000000000000..d9f019c3003da1 --- /dev/null +++ b/packages/expo-dev-menu/android/src/debug/res/drawable/code_brackets.xml @@ -0,0 +1,18 @@ + + + + diff --git a/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift b/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift index 0e8fc0c9585674..007330816539dc 100644 --- a/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift +++ b/packages/expo-dev-menu/ios/FAB/DevMenuFABView.swift @@ -52,7 +52,7 @@ struct FabPill: View { } if showLabel { - Text("Dev tools") + Text("Dev menu") .font(.system(size: 11, weight: .medium)) .foregroundStyle(.secondary) .fixedSize() diff --git a/packages/expo-dev-menu/ios/SwiftUI/DevMenuDeveloperTools.swift b/packages/expo-dev-menu/ios/SwiftUI/DevMenuDeveloperTools.swift index 4a8891f20b19dd..e223e4c0fdaf95 100644 --- a/packages/expo-dev-menu/ios/SwiftUI/DevMenuDeveloperTools.swift +++ b/packages/expo-dev-menu/ios/SwiftUI/DevMenuDeveloperTools.swift @@ -36,7 +36,7 @@ struct DevMenuDeveloperTools: View { Divider() #endif - + DevMenuActionButton( title: "Toggle performance monitor", icon: "speedometer", @@ -57,8 +57,8 @@ struct DevMenuDeveloperTools: View { Divider() DevMenuActionButton( - title: "Open JS debugger", - icon: "ladybug", + title: "Open DevTools", + icon: "chevron.left.chevron.right", action: viewModel.openJSInspector ) } @@ -79,7 +79,7 @@ struct DevMenuDeveloperTools: View { Divider() DevMenuToggleButton( - title: "Show dev tools button", + title: "Show dev menu button", icon: "hand.tap", isEnabled: viewModel.showFloatingActionButton, action: viewModel.toggleFloatingActionButton diff --git a/packages/expo-modules-core/android/src/main/java/expo/modules/rncompatibility/ReactNativeFeatureFlags.kt b/packages/expo-modules-core/android/src/main/java/expo/modules/rncompatibility/ReactNativeFeatureFlags.kt deleted file mode 100644 index 44706cf782d810..00000000000000 --- a/packages/expo-modules-core/android/src/main/java/expo/modules/rncompatibility/ReactNativeFeatureFlags.kt +++ /dev/null @@ -1,12 +0,0 @@ -package expo.modules.rncompatibility - -import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags - -/** - * A compatibility helper of - * `com.facebook.react.config.ReactFeatureFlags` and - * `com.facebook.react.internal.featureflags.ReactNativeFeatureFlags` - */ -object ReactNativeFeatureFlags { - val enableBridgelessArchitecture = ReactNativeFeatureFlags.enableBridgelessArchitecture() -} diff --git a/packages/expo-server/CHANGELOG.md b/packages/expo-server/CHANGELOG.md index dcfa1c665dfe95..885ee39c12c839 100644 --- a/packages/expo-server/CHANGELOG.md +++ b/packages/expo-server/CHANGELOG.md @@ -10,9 +10,12 @@ - Key loader data by `contextKey` instead of URL pathname ([#43017](https://github.com/expo/expo/pull/43017) by [@hassankhan] - Fix `setResponseHeaders()` failing on responses with immutable headers ([#43111](https://github.com/expo/expo/pull/43111) by [@hassankhan](https://github.com/hassankhan)) +- Fix `origin()` to properly default to `null` and use `request.url` in development ([#43143](https://github.com/expo/expo/pull/43143) by [@kitten](https://github.com/kitten)) ### ๐Ÿ’ก Others +- Add internal `preload` method to EAS and workerd request handlers ([#43171](https://github.com/expo/expo/pull/43171) by [@kitten](https://github.com/kitten)) + ## 55.0.3 โ€” 2026-02-03 ### ๐ŸŽ‰ New features diff --git a/packages/expo-server/build/cjs/runtime/api.d.ts b/packages/expo-server/build/cjs/runtime/api.d.ts index 4e37f040389232..7293c81e6cdb00 100644 --- a/packages/expo-server/build/cjs/runtime/api.d.ts +++ b/packages/expo-server/build/cjs/runtime/api.d.ts @@ -1,9 +1,10 @@ import { ImmutableHeaders } from '../ImmutableRequest'; export { StatusError } from './error'; -/** Returns the current request's origin URL. +/** Returns the current request's URL. * - * This typically returns the request's `Origin` header, which contains the - * request origin URL or defaults to `null`. + * This typically returns the request's URL, or on certain platform, + * the origin of the request. This does not use the `Origin` header + * in development as it may contain an untrusted value. * @returns A request origin */ export declare function origin(): string | null; diff --git a/packages/expo-server/build/cjs/runtime/api.js b/packages/expo-server/build/cjs/runtime/api.js index f27d0f9cdec96e..fd618c15175359 100644 --- a/packages/expo-server/build/cjs/runtime/api.js +++ b/packages/expo-server/build/cjs/runtime/api.js @@ -27,10 +27,11 @@ function assertSupport(name, v) { } var error_1 = require("./error"); Object.defineProperty(exports, "StatusError", { enumerable: true, get: function () { return error_1.StatusError; } }); -/** Returns the current request's origin URL. +/** Returns the current request's URL. * - * This typically returns the request's `Origin` header, which contains the - * request origin URL or defaults to `null`. + * This typically returns the request's URL, or on certain platform, + * the origin of the request. This does not use the `Origin` header + * in development as it may contain an untrusted value. * @returns A request origin */ function origin() { diff --git a/packages/expo-server/build/cjs/runtime/api.js.map b/packages/expo-server/build/cjs/runtime/api.js.map index 65940c904af4d0..74c3906d010522 100644 --- a/packages/expo-server/build/cjs/runtime/api.js.map +++ b/packages/expo-server/build/cjs/runtime/api.js.map @@ -1 +1 @@ -{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/runtime/api.ts"],"names":[],"mappings":";;;AAiCA,wBAEC;AAGD,wCAGC;AAUD,kCAEC;AAYD,0BAEC;AAWD,8BAEC;AAUD,gDAOC;AAjGD,0DAAuD;AACvD,mCAAoD;AAEpD,SAAS,oBAAoB;IAC3B,MAAM,KAAK,GAAG,gBAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,sDAAsD;YACtD,6EAA6E;YAC7E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAI,IAAY,EAAE,CAAgB;IACtD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,0DAA0D,CACvG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iCAAsC;AAA7B,oGAAA,WAAW,OAAA;AAEpB;;;;;GAKG;AACH,SAAgB,MAAM;IACpB,OAAO,aAAa,CAAC,UAAU,EAAE,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,kEAAkE;AAClE,SAAgB,cAAc;IAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC,cAAc,CAAC,CAAC;IACvF,OAAO,IAAI,mCAAgB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,WAAW;IACzB,OAAO,aAAa,CAAC,eAAe,EAAE,oBAAoB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,OAAO,CAAC,EAA0B;IAChD,aAAa,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,SAAS,CAAC,EAAiC;IACzD,aAAa,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,aAG0C;IAE1C,aAAa,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,CAAC,kBAAkB,CAAC,CAAC,aAAa,CAAC,CAAC;AAClG,CAAC"} \ No newline at end of file +{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/runtime/api.ts"],"names":[],"mappings":";;;AAkCA,wBAEC;AAGD,wCAGC;AAUD,kCAEC;AAYD,0BAEC;AAWD,8BAEC;AAUD,gDAOC;AAlGD,0DAAuD;AACvD,mCAAoD;AAEpD,SAAS,oBAAoB;IAC3B,MAAM,KAAK,GAAG,gBAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,sDAAsD;YACtD,6EAA6E;YAC7E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAI,IAAY,EAAE,CAAgB;IACtD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,0DAA0D,CACvG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,iCAAsC;AAA7B,oGAAA,WAAW,OAAA;AAEpB;;;;;;GAMG;AACH,SAAgB,MAAM;IACpB,OAAO,aAAa,CAAC,UAAU,EAAE,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,kEAAkE;AAClE,SAAgB,cAAc;IAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC,cAAc,CAAC,CAAC;IACvF,OAAO,IAAI,mCAAgB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,WAAW;IACzB,OAAO,aAAa,CAAC,eAAe,EAAE,oBAAoB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,OAAO,CAAC,EAA0B;IAChD,aAAa,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,SAAS,CAAC,EAAiC;IACzD,aAAa,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAChC,aAG0C;IAE1C,aAAa,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,CAAC,kBAAkB,CAAC,CAAC,aAAa,CAAC,CAAC;AAClG,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/runtime/index.d.ts b/packages/expo-server/build/cjs/runtime/index.d.ts index a667da2f774164..5ca4064c25ee5e 100644 --- a/packages/expo-server/build/cjs/runtime/index.d.ts +++ b/packages/expo-server/build/cjs/runtime/index.d.ts @@ -1,6 +1,6 @@ import { type ScopeDefinition, type RequestAPI } from './scope'; export interface RequestAPISetup extends RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; diff --git a/packages/expo-server/build/cjs/runtime/index.js b/packages/expo-server/build/cjs/runtime/index.js index b4b244ff3c15c1..0183e7294810a5 100644 --- a/packages/expo-server/build/cjs/runtime/index.js +++ b/packages/expo-server/build/cjs/runtime/index.js @@ -10,7 +10,9 @@ function setupRuntime() { enumerable: true, configurable: true, get() { - return scope_1.scopeRef.current?.getStore()?.origin || 'null'; + // NOTE(@kitten): By convention, this property must be a string, and runtimes typically + // choose to stringify "null" when the value is not available + return scope_1.scopeRef.current?.getStore()?.origin ?? 'null'; }, }); } diff --git a/packages/expo-server/build/cjs/runtime/index.js.map b/packages/expo-server/build/cjs/runtime/index.js.map index 7da809f0ab6661..8b6c814eb1ed0b 100644 --- a/packages/expo-server/build/cjs/runtime/index.js.map +++ b/packages/expo-server/build/cjs/runtime/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/runtime/scope.d.ts b/packages/expo-server/build/cjs/runtime/scope.d.ts index d3f703778196d2..f6772bc3d25ab2 100644 --- a/packages/expo-server/build/cjs/runtime/scope.d.ts +++ b/packages/expo-server/build/cjs/runtime/scope.d.ts @@ -1,6 +1,6 @@ export type UpdateResponseHeaders = Headers | Record | ((headers: Headers) => Headers | void); export interface RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; diff --git a/packages/expo-server/build/cjs/vendor/eas.d.ts b/packages/expo-server/build/cjs/vendor/eas.d.ts index 3994dbcaf3d115..cbc9efc0eef8b0 100644 --- a/packages/expo-server/build/cjs/vendor/eas.d.ts +++ b/packages/expo-server/build/cjs/vendor/eas.d.ts @@ -1,7 +1,10 @@ import { type RequestHandlerParams } from './abstract'; import { ExecutionContext } from './environment/workerd'; export { ExpoError } from './abstract'; -export type RequestHandler = (req: Request, env: Env, ctx: ExecutionContext) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} /** * Returns a request handler for EAS Hosting deployments. */ diff --git a/packages/expo-server/build/cjs/vendor/eas.js b/packages/expo-server/build/cjs/vendor/eas.js index ae237a40e9aedb..fad652747828dc 100644 --- a/packages/expo-server/build/cjs/vendor/eas.js +++ b/packages/expo-server/build/cjs/vendor/eas.js @@ -14,15 +14,17 @@ const STORE = new node_async_hooks_1.AsyncLocalStorage(); */ function createRequestHandler(params, setup) { const makeRequestAPISetup = (request, _env, ctx) => ({ - origin: request.headers.get('Origin') || 'null', + origin: request.headers.get('Origin') || null, environment: request.headers.get('eas-environment') || null, waitUntil: ctx.waitUntil?.bind(ctx), }); const run = (0, runtime_1.createRequestScope)(STORE, makeRequestAPISetup); - const onRequest = (0, abstract_1.createRequestHandler)({ - ...(0, workerd_1.createWorkerdEnv)(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = (0, workerd_1.createWorkerdEnv)(params); + const onRequest = (0, abstract_1.createRequestHandler)({ ...common, ...setup }); + function handler(request, env, ctx) { + return run(onRequest, request, env, ctx); + } + handler.preload = common.preload; + return handler; } //# sourceMappingURL=eas.js.map \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/eas.js.map b/packages/expo-server/build/cjs/vendor/eas.js.map index 8a5e8e8c233809..3ba26f45d45485 100644 --- a/packages/expo-server/build/cjs/vendor/eas.js.map +++ b/packages/expo-server/build/cjs/vendor/eas.js.map @@ -1 +1 @@ -{"version":3,"file":"eas.js","sourceRoot":"","sources":["../../../src/vendor/eas.ts"],"names":[],"mappings":";;;AAmBA,oDAeC;AAlCD,uDAAqD;AAErD,wCAAgD;AAChD,yCAAkG;AAClG,mDAA2E;AAE3E,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAQlB,MAAM,KAAK,GAAG,IAAI,oCAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,SAAgB,oBAAoB,CAClC,MAA0B,EAC1B,KAA4B;IAE5B,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,IAAS,EAAE,GAAqB,EAAE,EAAE,CAAC,CAAC;QACnF,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QAC/C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI;QAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAA,4BAAkB,EAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC;QAClC,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC;QAC3B,GAAG,KAAK;KACT,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC"} \ No newline at end of file +{"version":3,"file":"eas.js","sourceRoot":"","sources":["../../../src/vendor/eas.ts"],"names":[],"mappings":";;;AAkBA,oDAmBC;AArCD,uDAAqD;AAErD,wCAAgD;AAChD,yCAAkG;AAClG,mDAA2E;AAE3E,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAOlB,MAAM,KAAK,GAAG,IAAI,oCAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,SAAgB,oBAAoB,CAClC,MAA0B,EAC1B,KAA4B;IAE5B,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,IAAS,EAAE,GAAqB,EAAE,EAAE,CAAC,CAAC;QACnF,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;QAC7C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI;QAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAA,4BAAkB,EAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAE7D,SAAS,OAAO,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAAqB;QAChE,OAAO,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/environment/common.d.ts b/packages/expo-server/build/cjs/vendor/environment/common.d.ts index e3304e7f0d4168..8a3573f757bdff 100644 --- a/packages/expo-server/build/cjs/vendor/environment/common.d.ts +++ b/packages/expo-server/build/cjs/vendor/environment/common.d.ts @@ -5,11 +5,13 @@ interface EnvironmentInput { loadModule(request: string): Promise; isDevelopment: boolean; } -export declare function createEnvironment(input: EnvironmentInput): { - getRoutesManifest(): Promise; +export interface CommonEnvironment { + getRoutesManifest(): Promise; getHtml(request: Request, route: Route): Promise; getApiRoute(route: Route): Promise; getMiddleware(middleware: MiddlewareInfo): Promise; getLoaderData(request: Request, route: Route): Promise; -}; + preload(): Promise; +} +export declare function createEnvironment(input: EnvironmentInput): CommonEnvironment; export {}; diff --git a/packages/expo-server/build/cjs/vendor/environment/common.js b/packages/expo-server/build/cjs/vendor/environment/common.js index e33a899204b542..c2ce9d57bc463f 100644 --- a/packages/expo-server/build/cjs/vendor/environment/common.js +++ b/packages/expo-server/build/cjs/vendor/environment/common.js @@ -6,36 +6,36 @@ const matchers_1 = require("../../utils/matchers"); function initManifestRegExp(manifest) { return { ...manifest, - htmlRoutes: manifest.htmlRoutes.map((route) => ({ + htmlRoutes: manifest.htmlRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), - apiRoutes: manifest.apiRoutes.map((route) => ({ + })) ?? [], + apiRoutes: manifest.apiRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), - notFoundRoutes: manifest.notFoundRoutes.map((route) => ({ + })) ?? [], + notFoundRoutes: manifest.notFoundRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], redirects: manifest.redirects?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], rewrites: manifest.rewrites?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], }; } function createEnvironment(input) { // Cached manifest and SSR renderer, initialized on first request - let cachedManifest = null; + let cachedManifest; let ssrRenderer = null; - async function getCachedRoutesManifest() { - if (!cachedManifest || input.isDevelopment) { + async function getRoutesManifest() { + if (cachedManifest === undefined || input.isDevelopment) { const json = await input.readJson('_expo/routes.json'); - cachedManifest = initManifestRegExp(json); + cachedManifest = json ? initManifestRegExp(json) : null; } return cachedManifest; } @@ -43,8 +43,8 @@ function createEnvironment(input) { if (ssrRenderer && !input.isDevelopment) { return ssrRenderer; } - const manifest = await getCachedRoutesManifest(); - if (manifest.rendering?.mode !== 'ssr') { + const manifest = await getRoutesManifest(); + if (manifest?.rendering?.mode !== 'ssr') { return null; } // If `manifest.rendering.mode === 'ssr'`, we always expect the SSR rendering module to be @@ -76,9 +76,7 @@ function createEnvironment(input) { return loaderModule.loader(new ImmutableRequest_1.ImmutableRequest(request), params); } return { - async getRoutesManifest() { - return getCachedRoutesManifest(); - }, + getRoutesManifest, async getHtml(request, route) { // SSR path: Render at runtime if SSR module is available const renderer = await getServerRenderer(); @@ -137,6 +135,26 @@ function createEnvironment(input) { } return Response.json(result ?? null); }, + async preload() { + if (input.isDevelopment) { + return; + } + const manifest = await getRoutesManifest(); + if (manifest) { + const requests = []; + if (manifest.middleware) + requests.push(manifest.middleware.file); + if (manifest.rendering) + requests.push(manifest.rendering.file); + for (const apiRoute of manifest.apiRoutes) + requests.push(apiRoute.file); + for (const htmlRoute of manifest.htmlRoutes) { + if (htmlRoute.loader) + requests.push(htmlRoute.loader); + } + await Promise.all(requests.map((request) => input.loadModule(request))); + } + }, }; } //# sourceMappingURL=common.js.map \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/environment/common.js.map b/packages/expo-server/build/cjs/vendor/environment/common.js.map index 1053455aafa2e7..6ed03c46c278ee 100644 --- a/packages/expo-server/build/cjs/vendor/environment/common.js.map +++ b/packages/expo-server/build/cjs/vendor/environment/common.js.map @@ -1 +1 @@ -{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../src/vendor/environment/common.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../src/vendor/environment/common.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/environment/node.d.ts b/packages/expo-server/build/cjs/vendor/environment/node.d.ts index ef4c480719fd33..22066c97878763 100644 --- a/packages/expo-server/build/cjs/vendor/environment/node.d.ts +++ b/packages/expo-server/build/cjs/vendor/environment/node.d.ts @@ -1,15 +1,10 @@ +import { type CommonEnvironment } from './common'; import type { ScopeDefinition } from '../../runtime/scope'; interface NodeEnvParams { build: string; environment?: string | null; isDevelopment?: boolean; } -export declare function createNodeEnv(params: NodeEnvParams): { - getRoutesManifest(): Promise; - getHtml(request: Request, route: import("../../manifest").Route): Promise; - getApiRoute(route: import("../../manifest").Route): Promise; - getMiddleware(middleware: import("../../manifest").MiddlewareInfo): Promise; - getLoaderData(request: Request, route: import("../../manifest").Route): Promise; -}; +export declare function createNodeEnv(params: NodeEnvParams): CommonEnvironment; export declare function createNodeRequestScope(scopeDefinition: ScopeDefinition, params: NodeEnvParams): (fn: (request: Request) => Promise, request: Request) => Promise; export {}; diff --git a/packages/expo-server/build/cjs/vendor/environment/node.js b/packages/expo-server/build/cjs/vendor/environment/node.js index a3dcf636520922..aec737da0a7728 100644 --- a/packages/expo-server/build/cjs/vendor/environment/node.js +++ b/packages/expo-server/build/cjs/vendor/environment/node.js @@ -47,10 +47,19 @@ function createNodeEnv(params) { isDevelopment: params.isDevelopment ?? false, }); } +const getRequestURLOrigin = (request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } + catch { + return null; + } +}; function createNodeRequestScope(scopeDefinition, params) { return (0, runtime_1.createRequestScope)(scopeDefinition, (request) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? process.env.NODE_ENV, })); } diff --git a/packages/expo-server/build/cjs/vendor/environment/node.js.map b/packages/expo-server/build/cjs/vendor/environment/node.js.map index 8ec4b75cfcf0b9..5b2610558baedd 100644 --- a/packages/expo-server/build/cjs/vendor/environment/node.js.map +++ b/packages/expo-server/build/cjs/vendor/environment/node.js.map @@ -1 +1 @@ -{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../src/vendor/environment/node.ts"],"names":[],"mappings":";;;;;AAcA,sCAqCC;AAED,wDAMC;AA3DD,sDAAyB;AACzB,0DAA6B;AAE7B,qCAA6C;AAC7C,6DAAsE;AACtE,2CAAmD;AASnD,SAAgB,aAAa,CAAC,MAAqB;IACjD,IAAA,+CAA4B,GAAE,CAAC;IAE/B,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,iBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,OAAe;QACvC,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,IAAA,0BAAiB,EAAC;QACvB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,sBAAsB,CAAC,eAAgC,EAAE,MAAqB;IAC5F,OAAO,IAAA,4BAAkB,EAAC,eAAe,EAAE,CAAC,OAAgB,EAAE,EAAE,CAAC,CAAC;QAChE,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QAC/C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;KACxD,CAAC,CAAC,CAAC;AACN,CAAC"} \ No newline at end of file +{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../src/vendor/environment/node.ts"],"names":[],"mappings":";;;;;AAcA,sCAqCC;AAWD,wDAMC;AApED,sDAAyB;AACzB,0DAA6B;AAE7B,qCAAqE;AACrE,6DAAsE;AACtE,2CAAmD;AASnD,SAAgB,aAAa,CAAC,MAAqB;IACjD,IAAA,+CAA4B,GAAE,CAAC;IAE/B,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,iBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,OAAe;QACvC,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,iBAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,IAAA,0BAAiB,EAAC;QACvB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,EAAE;IAC/C,IAAI,CAAC;QACH,8EAA8E;QAC9E,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,SAAgB,sBAAsB,CAAC,eAAgC,EAAE,MAAqB;IAC5F,OAAO,IAAA,4BAAkB,EAAC,eAAe,EAAE,CAAC,OAAgB,EAAE,EAAE,CAAC,CAAC;QAChE,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;QACpC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;KACxD,CAAC,CAAC,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/environment/workerd.d.ts b/packages/expo-server/build/cjs/vendor/environment/workerd.d.ts index 4ea6f6ee5e23c9..ffc193452a9d02 100644 --- a/packages/expo-server/build/cjs/vendor/environment/workerd.d.ts +++ b/packages/expo-server/build/cjs/vendor/environment/workerd.d.ts @@ -1,16 +1,11 @@ +import { type CommonEnvironment } from './common'; import type { ScopeDefinition } from '../../runtime/scope'; interface WorkerdEnvParams { build?: string; environment?: string | null; isDevelopment?: boolean; } -export declare function createWorkerdEnv(params: WorkerdEnvParams): { - getRoutesManifest(): Promise; - getHtml(request: Request, route: import("../../manifest").Route): Promise; - getApiRoute(route: import("../../manifest").Route): Promise; - getMiddleware(middleware: import("../../manifest").MiddlewareInfo): Promise; - getLoaderData(request: Request, route: import("../../manifest").Route): Promise; -}; +export declare function createWorkerdEnv(params: WorkerdEnvParams): CommonEnvironment; export interface ExecutionContext { waitUntil?(promise: Promise): void; props?: any; diff --git a/packages/expo-server/build/cjs/vendor/environment/workerd.js b/packages/expo-server/build/cjs/vendor/environment/workerd.js index 484802bfa1ff58..099dc6e305607d 100644 --- a/packages/expo-server/build/cjs/vendor/environment/workerd.js +++ b/packages/expo-server/build/cjs/vendor/environment/workerd.js @@ -62,10 +62,19 @@ function createWorkerdEnv(params) { isDevelopment: params.isDevelopment ?? false, }); } +const getRequestURLOrigin = (request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } + catch { + return null; + } +}; function createWorkerdRequestScope(scopeDefinition, params) { const makeRequestAPISetup = (request, _env, ctx) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? null, waitUntil: ctx.waitUntil?.bind(ctx), }); diff --git a/packages/expo-server/build/cjs/vendor/environment/workerd.js.map b/packages/expo-server/build/cjs/vendor/environment/workerd.js.map index 8423e939c7914c..3a5beba9724776 100644 --- a/packages/expo-server/build/cjs/vendor/environment/workerd.js.map +++ b/packages/expo-server/build/cjs/vendor/environment/workerd.js.map @@ -1 +1 @@ -{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../../src/vendor/environment/workerd.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../../src/vendor/environment/workerd.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/netlify.js b/packages/expo-server/build/cjs/vendor/netlify.js index 75d3228a0981fa..47627559d5b822 100644 --- a/packages/expo-server/build/cjs/vendor/netlify.js +++ b/packages/expo-server/build/cjs/vendor/netlify.js @@ -29,7 +29,7 @@ const STORE = { }; function createRequestHandler(params) { const makeRequestAPISetup = (request, context) => ({ - origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || 'null', + origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || null, environment: (context ?? getContext()).deploy?.context || null, waitUntil: (context ?? getContext()).waitUntil, }); diff --git a/packages/expo-server/build/cjs/vendor/netlify.js.map b/packages/expo-server/build/cjs/vendor/netlify.js.map index bf9d5bc54e33ef..ab8bdcdb53dd68 100644 --- a/packages/expo-server/build/cjs/vendor/netlify.js.map +++ b/packages/expo-server/build/cjs/vendor/netlify.js.map @@ -1 +1 @@ -{"version":3,"file":"netlify.js","sourceRoot":"","sources":["../../../src/vendor/netlify.ts"],"names":[],"mappings":";;;AAyCA,oDAiBC;AA1DD,yCAAuE;AACvE,wCAAgD;AAChD,6CAAmD;AAGnD,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAElB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AASlD,yFAAyF;AACzF,SAAS,UAAU;IACjB,MAAM,UAAU,GAEZ,UAAU,CAAC;IACf,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iDAAiD;YAC/C,gEAAgE;YAChE,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAClF,mCAAmC;AACnC,MAAM,KAAK,GAAoB;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;IACzC,GAAG,CAAC,KAAU,EAAE,MAA+B,EAAE,GAAG,IAAW;QAC7D,UAAU,EAAE,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC;AAEF,SAAgB,oBAAoB,CAAC,MAAyB;IAC5D,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,OAAwB,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QACtF,WAAW,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;QAC9D,SAAS,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,SAAS;KAC/C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAA,4BAAkB,EAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC,IAAA,oBAAa,EAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAoB,EAAE,EAAE;QAClD,IAAI,mBAAmB,IAAI,GAAG,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC3E,wFAAwF,CAC3F,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"netlify.js","sourceRoot":"","sources":["../../../src/vendor/netlify.ts"],"names":[],"mappings":";;;AAyCA,oDAiBC;AA1DD,yCAAuE;AACvE,wCAAgD;AAChD,6CAAmD;AAGnD,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAElB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AASlD,yFAAyF;AACzF,SAAS,UAAU;IACjB,MAAM,UAAU,GAEZ,UAAU,CAAC;IACf,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iDAAiD;YAC/C,gEAAgE;YAChE,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAClF,mCAAmC;AACnC,MAAM,KAAK,GAAoB;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;IACzC,GAAG,CAAC,KAAU,EAAE,MAA+B,EAAE,GAAG,IAAW;QAC7D,UAAU,EAAE,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC;AAEF,SAAgB,oBAAoB,CAAC,MAAyB;IAC5D,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,OAAwB,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;QACpF,WAAW,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;QAC9D,SAAS,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,SAAS;KAC/C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,IAAA,4BAAkB,EAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC,IAAA,oBAAa,EAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAoB,EAAE,EAAE;QAClD,IAAI,mBAAmB,IAAI,GAAG,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC3E,wFAAwF,CAC3F,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/vercel.js b/packages/expo-server/build/cjs/vendor/vercel.js index e443b7c780288b..62fbe81687b5ca 100644 --- a/packages/expo-server/build/cjs/vendor/vercel.js +++ b/packages/expo-server/build/cjs/vendor/vercel.js @@ -38,7 +38,7 @@ function createRequestHandler(params) { const host = request.headers.get('host'); const proto = request.headers.get('x-forwarded-proto') || 'https'; return { - origin: host ? `${proto}://${host}` : 'null', + origin: host ? `${proto}://${host}` : null, // See: https://github.com/vercel/vercel/blob/b189b39/packages/functions/src/get-env.ts#L25C3-L25C13 environment: process.env.VERCEL_ENV ?? process.env.NODE_ENV, waitUntil: getContext().waitUntil, diff --git a/packages/expo-server/build/cjs/vendor/vercel.js.map b/packages/expo-server/build/cjs/vendor/vercel.js.map index e2268d22036798..0c3f317501f359 100644 --- a/packages/expo-server/build/cjs/vendor/vercel.js.map +++ b/packages/expo-server/build/cjs/vendor/vercel.js.map @@ -1 +1 @@ -{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../src/vendor/vercel.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../src/vendor/vercel.ts"],"names":[],"mappings":";;;AAiDA,oDAgBC;AAED,wCAcC;AAUD,wCA0BC;AAED,0BAQC;AA3HD,6CAAuC;AACvC,mDAAgD;AAGhD,yCAAuE;AACvE,wCAAgD;AAChD,6CAAmD;AAEnD,gGAA6F;AAE7F,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAIlB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AAOlD,MAAM,sBAAsB,GAAG,MAAM,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;AAErE,+FAA+F;AAC/F,SAAS,UAAU;IACjB,MAAM,UAAU,GAEZ,UAAU,CAAC;IACf,OAAO,UAAU,CAAC,sBAAsB,CAAC,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;AAC3D,CAAC;AAED,gFAAgF;AAChF,mCAAmC;AACnC,MAAM,KAAK,GAAoB;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;IACzC,GAAG,CAAC,KAAU,EAAE,MAA+B,EAAE,GAAG,IAAW;QAC7D,UAAU,EAAE,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC;AAEF;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,MAAyB;IAC5D,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,EAAE;QAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,OAAO,CAAC;QAClE,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI;YAC1C,oGAAoG;YACpG,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;YAC3D,SAAS,EAAE,UAAU,EAAE,CAAC,SAAS;SAClC,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,IAAA,4BAAkB,EAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC,IAAA,oBAAa,EAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACxB,OAAO,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,SAAS,EAAE,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc,CAAC,cAA+C;IAC5E,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC3D,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBAC7B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,cAAiC;IAC1D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,cAAc,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC9D,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAgB,cAAc,CAAC,GAAyB,EAAE,GAAwB;IAChF,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpE,oDAAoD;IACpD,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,OAAO,CAAC;IAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,QAAQ,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;IAEvD,8DAA8D;IAC9D,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,CAAC;IAE1C,MAAM,IAAI,GAAgB;QACxB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1C,yCAAyC;QACzC,2DAA2D;QAC3D,MAAM,EAAE,UAAU,CAAC,MAA+B;KACnD,CAAC;IAEF,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAClD,4FAA4F;QAC5F,qFAAqF;QACrF,IAAI,CAAC,IAAI,GAAG,IAAA,mEAAgC,EAAC,GAAG,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAEM,KAAK,UAAU,OAAO,CAAC,GAAwB,EAAE,OAAiB;IACvE,GAAG,CAAC,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC;IACvC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACzF,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAA,mBAAQ,EAAC,sBAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAA0B,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5E,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/workerd.d.ts b/packages/expo-server/build/cjs/vendor/workerd.d.ts index 3e9bf7a1bdcf0b..5fc08b17c6f430 100644 --- a/packages/expo-server/build/cjs/vendor/workerd.d.ts +++ b/packages/expo-server/build/cjs/vendor/workerd.d.ts @@ -1,7 +1,10 @@ import { type RequestHandlerParams } from './abstract'; import { ExecutionContext } from './environment/workerd'; export { ExpoError } from './abstract'; -export type RequestHandler = (req: Request, env: Env, ctx: ExecutionContext) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} /** * Returns a request handler for Workerd deployments. */ diff --git a/packages/expo-server/build/cjs/vendor/workerd.js b/packages/expo-server/build/cjs/vendor/workerd.js index 39513c54679934..90ce7d2fd0f365 100644 --- a/packages/expo-server/build/cjs/vendor/workerd.js +++ b/packages/expo-server/build/cjs/vendor/workerd.js @@ -13,10 +13,12 @@ const STORE = new node_async_hooks_1.AsyncLocalStorage(); */ function createRequestHandler(params, setup) { const run = (0, workerd_1.createWorkerdRequestScope)(STORE, params); - const onRequest = (0, abstract_1.createRequestHandler)({ - ...(0, workerd_1.createWorkerdEnv)(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = (0, workerd_1.createWorkerdEnv)(params); + const onRequest = (0, abstract_1.createRequestHandler)({ ...common, ...setup }); + function handler(request, env, ctx) { + return run(onRequest, request, env, ctx); + } + handler.preload = common.preload; + return handler; } //# sourceMappingURL=workerd.js.map \ No newline at end of file diff --git a/packages/expo-server/build/cjs/vendor/workerd.js.map b/packages/expo-server/build/cjs/vendor/workerd.js.map index 6a46f0d0427350..c0802ba844e71b 100644 --- a/packages/expo-server/build/cjs/vendor/workerd.js.map +++ b/packages/expo-server/build/cjs/vendor/workerd.js.map @@ -1 +1 @@ -{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../src/vendor/workerd.ts"],"names":[],"mappings":";;;AAsBA,oDAUC;AAhCD,uDAAqD;AAErD,yCAAkG;AAClG,mDAI+B;AAE/B,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAQlB,MAAM,KAAK,GAAG,IAAI,oCAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,SAAgB,oBAAoB,CAClC,MAAsD,EACtD,KAA4B;IAE5B,MAAM,GAAG,GAAG,IAAA,mCAAyB,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC;QAClC,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC;QAC3B,GAAG,KAAK;KACT,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC"} \ No newline at end of file +{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../src/vendor/workerd.ts"],"names":[],"mappings":";;;AAqBA,oDAcC;AAnCD,uDAAqD;AAErD,yCAAkG;AAClG,mDAI+B;AAE/B,uCAAuC;AAA9B,qGAAA,SAAS,OAAA;AAOlB,MAAM,KAAK,GAAG,IAAI,oCAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,SAAgB,oBAAoB,CAClC,MAAsD,EACtD,KAA4B;IAE5B,MAAM,GAAG,GAAG,IAAA,mCAAyB,EAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAA,0BAAgB,EAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAA,+BAAiB,EAAC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAE7D,SAAS,OAAO,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAAqB;QAChE,OAAO,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/runtime/api.d.ts b/packages/expo-server/build/mjs/runtime/api.d.ts index 4e37f040389232..7293c81e6cdb00 100644 --- a/packages/expo-server/build/mjs/runtime/api.d.ts +++ b/packages/expo-server/build/mjs/runtime/api.d.ts @@ -1,9 +1,10 @@ import { ImmutableHeaders } from '../ImmutableRequest'; export { StatusError } from './error'; -/** Returns the current request's origin URL. +/** Returns the current request's URL. * - * This typically returns the request's `Origin` header, which contains the - * request origin URL or defaults to `null`. + * This typically returns the request's URL, or on certain platform, + * the origin of the request. This does not use the `Origin` header + * in development as it may contain an untrusted value. * @returns A request origin */ export declare function origin(): string | null; diff --git a/packages/expo-server/build/mjs/runtime/api.js b/packages/expo-server/build/mjs/runtime/api.js index adda218bf456b2..5654bf355d32ea 100644 --- a/packages/expo-server/build/mjs/runtime/api.js +++ b/packages/expo-server/build/mjs/runtime/api.js @@ -17,10 +17,11 @@ function assertSupport(name, v) { return v; } export { StatusError } from './error'; -/** Returns the current request's origin URL. +/** Returns the current request's URL. * - * This typically returns the request's `Origin` header, which contains the - * request origin URL or defaults to `null`. + * This typically returns the request's URL, or on certain platform, + * the origin of the request. This does not use the `Origin` header + * in development as it may contain an untrusted value. * @returns A request origin */ export function origin() { diff --git a/packages/expo-server/build/mjs/runtime/api.js.map b/packages/expo-server/build/mjs/runtime/api.js.map index fd3df22920cf72..09e327bc1c5d25 100644 --- a/packages/expo-server/build/mjs/runtime/api.js.map +++ b/packages/expo-server/build/mjs/runtime/api.js.map @@ -1 +1 @@ -{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/runtime/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAmB,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,SAAS,oBAAoB;IAC3B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,sDAAsD;YACtD,6EAA6E;YAC7E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAI,IAAY,EAAE,CAAgB;IACtD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,0DAA0D,CACvG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,aAAa,CAAC,UAAU,EAAE,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC,cAAc,CAAC,CAAC;IACvF,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,aAAa,CAAC,eAAe,EAAE,oBAAoB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,OAAO,CAAC,EAA0B;IAChD,aAAa,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,EAAiC;IACzD,aAAa,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAG0C;IAE1C,aAAa,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,CAAC,kBAAkB,CAAC,CAAC,aAAa,CAAC,CAAC;AAClG,CAAC"} \ No newline at end of file +{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/runtime/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAmB,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,SAAS,oBAAoB;IAC3B,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC3C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6FAA6F;YAC3F,sDAAsD;YACtD,6EAA6E;YAC7E,4DAA4D,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAI,IAAY,EAAE,CAAgB;IACtD,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,0DAA0D,CACvG,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,aAAa,CAAC,UAAU,EAAE,oBAAoB,EAAE,CAAC,MAAM,CAAC,CAAC;AAClE,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,cAAc;IAC5B,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC,cAAc,CAAC,CAAC;IACvF,OAAO,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,aAAa,CAAC,eAAe,EAAE,oBAAoB,EAAE,CAAC,WAAW,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,OAAO,CAAC,EAA0B;IAChD,aAAa,CAAC,WAAW,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,EAAiC;IACzD,aAAa,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAG0C;IAE1C,aAAa,CAAC,sBAAsB,EAAE,oBAAoB,EAAE,CAAC,kBAAkB,CAAC,CAAC,aAAa,CAAC,CAAC;AAClG,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/runtime/index.d.ts b/packages/expo-server/build/mjs/runtime/index.d.ts index a667da2f774164..5ca4064c25ee5e 100644 --- a/packages/expo-server/build/mjs/runtime/index.d.ts +++ b/packages/expo-server/build/mjs/runtime/index.d.ts @@ -1,6 +1,6 @@ import { type ScopeDefinition, type RequestAPI } from './scope'; export interface RequestAPISetup extends RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; diff --git a/packages/expo-server/build/mjs/runtime/index.js b/packages/expo-server/build/mjs/runtime/index.js index 3f8d5639321f6c..71e89187fe5642 100644 --- a/packages/expo-server/build/mjs/runtime/index.js +++ b/packages/expo-server/build/mjs/runtime/index.js @@ -7,7 +7,9 @@ function setupRuntime() { enumerable: true, configurable: true, get() { - return scopeRef.current?.getStore()?.origin || 'null'; + // NOTE(@kitten): By convention, this property must be a string, and runtimes typically + // choose to stringify "null" when the value is not available + return scopeRef.current?.getStore()?.origin ?? 'null'; }, }); } diff --git a/packages/expo-server/build/mjs/runtime/index.js.map b/packages/expo-server/build/mjs/runtime/index.js.map index 81133c0cf8e716..bf0d716157a4bd 100644 --- a/packages/expo-server/build/mjs/runtime/index.js.map +++ b/packages/expo-server/build/mjs/runtime/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/runtime/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/runtime/scope.d.ts b/packages/expo-server/build/mjs/runtime/scope.d.ts index d3f703778196d2..f6772bc3d25ab2 100644 --- a/packages/expo-server/build/mjs/runtime/scope.d.ts +++ b/packages/expo-server/build/mjs/runtime/scope.d.ts @@ -1,6 +1,6 @@ export type UpdateResponseHeaders = Headers | Record | ((headers: Headers) => Headers | void); export interface RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; diff --git a/packages/expo-server/build/mjs/vendor/eas.d.ts b/packages/expo-server/build/mjs/vendor/eas.d.ts index 3994dbcaf3d115..cbc9efc0eef8b0 100644 --- a/packages/expo-server/build/mjs/vendor/eas.d.ts +++ b/packages/expo-server/build/mjs/vendor/eas.d.ts @@ -1,7 +1,10 @@ import { type RequestHandlerParams } from './abstract'; import { ExecutionContext } from './environment/workerd'; export { ExpoError } from './abstract'; -export type RequestHandler = (req: Request, env: Env, ctx: ExecutionContext) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} /** * Returns a request handler for EAS Hosting deployments. */ diff --git a/packages/expo-server/build/mjs/vendor/eas.js b/packages/expo-server/build/mjs/vendor/eas.js index 04af3733d3c03d..c155983726857d 100644 --- a/packages/expo-server/build/mjs/vendor/eas.js +++ b/packages/expo-server/build/mjs/vendor/eas.js @@ -9,15 +9,17 @@ const STORE = new AsyncLocalStorage(); */ export function createRequestHandler(params, setup) { const makeRequestAPISetup = (request, _env, ctx) => ({ - origin: request.headers.get('Origin') || 'null', + origin: request.headers.get('Origin') || null, environment: request.headers.get('eas-environment') || null, waitUntil: ctx.waitUntil?.bind(ctx), }); const run = createRequestScope(STORE, makeRequestAPISetup); - const onRequest = createExpoHandler({ - ...createWorkerdEnv(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = createWorkerdEnv(params); + const onRequest = createExpoHandler({ ...common, ...setup }); + function handler(request, env, ctx) { + return run(onRequest, request, env, ctx); + } + handler.preload = common.preload; + return handler; } //# sourceMappingURL=eas.js.map \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/eas.js.map b/packages/expo-server/build/mjs/vendor/eas.js.map index 0d694e8d78b4e9..be58328994d247 100644 --- a/packages/expo-server/build/mjs/vendor/eas.js.map +++ b/packages/expo-server/build/mjs/vendor/eas.js.map @@ -1 +1 @@ -{"version":3,"file":"eas.js","sourceRoot":"","sources":["../../../src/vendor/eas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAA6B,MAAM,YAAY,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE3E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQvC,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAA0B,EAC1B,KAA4B;IAE5B,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,IAAS,EAAE,GAAqB,EAAE,EAAE,CAAC,CAAC;QACnF,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QAC/C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI;QAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,iBAAiB,CAAC;QAClC,GAAG,gBAAgB,CAAC,MAAM,CAAC;QAC3B,GAAG,KAAK;KACT,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC"} \ No newline at end of file +{"version":3,"file":"eas.js","sourceRoot":"","sources":["../../../src/vendor/eas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAA6B,MAAM,YAAY,CAAC;AAClG,OAAO,EAAE,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE3E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAA0B,EAC1B,KAA4B;IAE5B,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,IAAS,EAAE,GAAqB,EAAE,EAAE,CAAC,CAAC;QACnF,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;QAC7C,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,IAAI;QAC3D,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,iBAAiB,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAE7D,SAAS,OAAO,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAAqB;QAChE,OAAO,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/environment/common.d.ts b/packages/expo-server/build/mjs/vendor/environment/common.d.ts index e3304e7f0d4168..8a3573f757bdff 100644 --- a/packages/expo-server/build/mjs/vendor/environment/common.d.ts +++ b/packages/expo-server/build/mjs/vendor/environment/common.d.ts @@ -5,11 +5,13 @@ interface EnvironmentInput { loadModule(request: string): Promise; isDevelopment: boolean; } -export declare function createEnvironment(input: EnvironmentInput): { - getRoutesManifest(): Promise; +export interface CommonEnvironment { + getRoutesManifest(): Promise; getHtml(request: Request, route: Route): Promise; getApiRoute(route: Route): Promise; getMiddleware(middleware: MiddlewareInfo): Promise; getLoaderData(request: Request, route: Route): Promise; -}; + preload(): Promise; +} +export declare function createEnvironment(input: EnvironmentInput): CommonEnvironment; export {}; diff --git a/packages/expo-server/build/mjs/vendor/environment/common.js b/packages/expo-server/build/mjs/vendor/environment/common.js index 6fe50928ad00ed..5b2a58c93085de 100644 --- a/packages/expo-server/build/mjs/vendor/environment/common.js +++ b/packages/expo-server/build/mjs/vendor/environment/common.js @@ -3,36 +3,36 @@ import { isResponse, parseParams, resolveLoaderContextKey } from '../../utils/ma function initManifestRegExp(manifest) { return { ...manifest, - htmlRoutes: manifest.htmlRoutes.map((route) => ({ + htmlRoutes: manifest.htmlRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), - apiRoutes: manifest.apiRoutes.map((route) => ({ + })) ?? [], + apiRoutes: manifest.apiRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), - notFoundRoutes: manifest.notFoundRoutes.map((route) => ({ + })) ?? [], + notFoundRoutes: manifest.notFoundRoutes?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], redirects: manifest.redirects?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], rewrites: manifest.rewrites?.map((route) => ({ ...route, namedRegex: new RegExp(route.namedRegex), - })), + })) ?? [], }; } export function createEnvironment(input) { // Cached manifest and SSR renderer, initialized on first request - let cachedManifest = null; + let cachedManifest; let ssrRenderer = null; - async function getCachedRoutesManifest() { - if (!cachedManifest || input.isDevelopment) { + async function getRoutesManifest() { + if (cachedManifest === undefined || input.isDevelopment) { const json = await input.readJson('_expo/routes.json'); - cachedManifest = initManifestRegExp(json); + cachedManifest = json ? initManifestRegExp(json) : null; } return cachedManifest; } @@ -40,8 +40,8 @@ export function createEnvironment(input) { if (ssrRenderer && !input.isDevelopment) { return ssrRenderer; } - const manifest = await getCachedRoutesManifest(); - if (manifest.rendering?.mode !== 'ssr') { + const manifest = await getRoutesManifest(); + if (manifest?.rendering?.mode !== 'ssr') { return null; } // If `manifest.rendering.mode === 'ssr'`, we always expect the SSR rendering module to be @@ -73,9 +73,7 @@ export function createEnvironment(input) { return loaderModule.loader(new ImmutableRequest(request), params); } return { - async getRoutesManifest() { - return getCachedRoutesManifest(); - }, + getRoutesManifest, async getHtml(request, route) { // SSR path: Render at runtime if SSR module is available const renderer = await getServerRenderer(); @@ -134,6 +132,26 @@ export function createEnvironment(input) { } return Response.json(result ?? null); }, + async preload() { + if (input.isDevelopment) { + return; + } + const manifest = await getRoutesManifest(); + if (manifest) { + const requests = []; + if (manifest.middleware) + requests.push(manifest.middleware.file); + if (manifest.rendering) + requests.push(manifest.rendering.file); + for (const apiRoute of manifest.apiRoutes) + requests.push(apiRoute.file); + for (const htmlRoute of manifest.htmlRoutes) { + if (htmlRoute.loader) + requests.push(htmlRoute.loader); + } + await Promise.all(requests.map((request) => input.loadModule(request))); + } + }, }; } //# sourceMappingURL=common.js.map \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/environment/common.js.map b/packages/expo-server/build/mjs/vendor/environment/common.js.map index 3401fe9fd925d9..af7354e9a3d79e 100644 --- a/packages/expo-server/build/mjs/vendor/environment/common.js.map +++ b/packages/expo-server/build/mjs/vendor/environment/common.js.map @@ -1 +1 @@ -{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../src/vendor/environment/common.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"common.js","sourceRoot":"","sources":["../../../../src/vendor/environment/common.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/environment/node.d.ts b/packages/expo-server/build/mjs/vendor/environment/node.d.ts index ef4c480719fd33..22066c97878763 100644 --- a/packages/expo-server/build/mjs/vendor/environment/node.d.ts +++ b/packages/expo-server/build/mjs/vendor/environment/node.d.ts @@ -1,15 +1,10 @@ +import { type CommonEnvironment } from './common'; import type { ScopeDefinition } from '../../runtime/scope'; interface NodeEnvParams { build: string; environment?: string | null; isDevelopment?: boolean; } -export declare function createNodeEnv(params: NodeEnvParams): { - getRoutesManifest(): Promise; - getHtml(request: Request, route: import("../../manifest").Route): Promise; - getApiRoute(route: import("../../manifest").Route): Promise; - getMiddleware(middleware: import("../../manifest").MiddlewareInfo): Promise; - getLoaderData(request: Request, route: import("../../manifest").Route): Promise; -}; +export declare function createNodeEnv(params: NodeEnvParams): CommonEnvironment; export declare function createNodeRequestScope(scopeDefinition: ScopeDefinition, params: NodeEnvParams): (fn: (request: Request) => Promise, request: Request) => Promise; export {}; diff --git a/packages/expo-server/build/mjs/vendor/environment/node.js b/packages/expo-server/build/mjs/vendor/environment/node.js index 0aab5b80a36190..56a4327cc6650e 100644 --- a/packages/expo-server/build/mjs/vendor/environment/node.js +++ b/packages/expo-server/build/mjs/vendor/environment/node.js @@ -40,10 +40,19 @@ export function createNodeEnv(params) { isDevelopment: params.isDevelopment ?? false, }); } +const getRequestURLOrigin = (request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } + catch { + return null; + } +}; export function createNodeRequestScope(scopeDefinition, params) { return createRequestScope(scopeDefinition, (request) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? process.env.NODE_ENV, })); } diff --git a/packages/expo-server/build/mjs/vendor/environment/node.js.map b/packages/expo-server/build/mjs/vendor/environment/node.js.map index a7bbdff97514f7..deebe9c735c377 100644 --- a/packages/expo-server/build/mjs/vendor/environment/node.js.map +++ b/packages/expo-server/build/mjs/vendor/environment/node.js.map @@ -1 +1 @@ -{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../src/vendor/environment/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AASnD,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,4BAA4B,EAAE,CAAC;IAE/B,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,OAAe;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,iBAAiB,CAAC;QACvB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,eAAgC,EAAE,MAAqB;IAC5F,OAAO,kBAAkB,CAAC,eAAe,EAAE,CAAC,OAAgB,EAAE,EAAE,CAAC,CAAC;QAChE,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QAC/C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;KACxD,CAAC,CAAC,CAAC;AACN,CAAC"} \ No newline at end of file +{"version":3,"file":"node.js","sourceRoot":"","sources":["../../../../src/vendor/environment/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAA0B,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AASnD,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,4BAA4B,EAAE,CAAC;IAE/B,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChD,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,OAAe;QACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;aAAM,IAAI,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,OAAO,iBAAiB,CAAC;QACvB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,EAAE;IAC/C,IAAI,CAAC;QACH,8EAA8E;QAC9E,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,eAAgC,EAAE,MAAqB;IAC5F,OAAO,kBAAkB,CAAC,eAAe,EAAE,CAAC,OAAgB,EAAE,EAAE,CAAC,CAAC;QAChE,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;QACpC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;KACxD,CAAC,CAAC,CAAC;AACN,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/environment/workerd.d.ts b/packages/expo-server/build/mjs/vendor/environment/workerd.d.ts index 4ea6f6ee5e23c9..ffc193452a9d02 100644 --- a/packages/expo-server/build/mjs/vendor/environment/workerd.d.ts +++ b/packages/expo-server/build/mjs/vendor/environment/workerd.d.ts @@ -1,16 +1,11 @@ +import { type CommonEnvironment } from './common'; import type { ScopeDefinition } from '../../runtime/scope'; interface WorkerdEnvParams { build?: string; environment?: string | null; isDevelopment?: boolean; } -export declare function createWorkerdEnv(params: WorkerdEnvParams): { - getRoutesManifest(): Promise; - getHtml(request: Request, route: import("../../manifest").Route): Promise; - getApiRoute(route: import("../../manifest").Route): Promise; - getMiddleware(middleware: import("../../manifest").MiddlewareInfo): Promise; - getLoaderData(request: Request, route: import("../../manifest").Route): Promise; -}; +export declare function createWorkerdEnv(params: WorkerdEnvParams): CommonEnvironment; export interface ExecutionContext { waitUntil?(promise: Promise): void; props?: any; diff --git a/packages/expo-server/build/mjs/vendor/environment/workerd.js b/packages/expo-server/build/mjs/vendor/environment/workerd.js index d88632222d351a..138d3c3d83f7c7 100644 --- a/packages/expo-server/build/mjs/vendor/environment/workerd.js +++ b/packages/expo-server/build/mjs/vendor/environment/workerd.js @@ -58,10 +58,19 @@ export function createWorkerdEnv(params) { isDevelopment: params.isDevelopment ?? false, }); } +const getRequestURLOrigin = (request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } + catch { + return null; + } +}; export function createWorkerdRequestScope(scopeDefinition, params) { const makeRequestAPISetup = (request, _env, ctx) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? null, waitUntil: ctx.waitUntil?.bind(ctx), }); diff --git a/packages/expo-server/build/mjs/vendor/environment/workerd.js.map b/packages/expo-server/build/mjs/vendor/environment/workerd.js.map index ea5e4fc9e08abd..cfada2a0acb68c 100644 --- a/packages/expo-server/build/mjs/vendor/environment/workerd.js.map +++ b/packages/expo-server/build/mjs/vendor/environment/workerd.js.map @@ -1 +1 @@ -{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../../src/vendor/environment/workerd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGnD,MAAM,kBAAkB,GAAG,GAAG,EAAE;IAC9B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAyD,CAAC;IACrF,OAAO,KAAK,UAAU,YAAY,CAAU,OAAe;QACzD,IAAI,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAC3C,CAAC;YACD,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,KAAU,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,CAAC,KAAK,CAAC;QACrB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC;AAQF,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC;IAClC,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;IAE1C,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAsB,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;YAC3E,OAAO,GAAG,CAAC,OAAO,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,QAAQ,CAAC,OAAe;QACrC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC,CAAC;YACtD,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBAC9D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,OAAO,GAAG,CAAC,OAAO,CAAC;YACrB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,UAAU,UAAU,CAAC,OAAe;QACvC,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;QACrC,OAAO,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IACxC,CAAC;IAED,OAAO,iBAAiB,CAAC;QACvB,QAAQ;QACR,QAAQ;QACR,UAAU;QACV,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,KAAK;KAC7C,CAAC,CAAC;AACL,CAAC;AAOD,MAAM,UAAU,yBAAyB,CACvC,eAAgC,EAChC,MAAwB;IAExB,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,IAAS,EAAE,GAAqB,EAAE,EAAE,CAAC,CAAC;QACnF,cAAc,EAAE,OAAO,CAAC,OAAO;QAC/B,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QAC/C,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;QACvC,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC;KACpC,CAAC,CAAC;IACH,OAAO,kBAAkB,CAAC,eAAe,EAAE,mBAAmB,CAAC,CAAC;AAClE,CAAC"} \ No newline at end of file +{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../../src/vendor/environment/workerd.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/netlify.js b/packages/expo-server/build/mjs/vendor/netlify.js index c0877b61530749..41b97e9bc18635 100644 --- a/packages/expo-server/build/mjs/vendor/netlify.js +++ b/packages/expo-server/build/mjs/vendor/netlify.js @@ -24,7 +24,7 @@ const STORE = { }; export function createRequestHandler(params) { const makeRequestAPISetup = (request, context) => ({ - origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || 'null', + origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || null, environment: (context ?? getContext()).deploy?.context || null, waitUntil: (context ?? getContext()).waitUntil, }); diff --git a/packages/expo-server/build/mjs/vendor/netlify.js.map b/packages/expo-server/build/mjs/vendor/netlify.js.map index 65c29905034e4d..f5a19715a2fcb0 100644 --- a/packages/expo-server/build/mjs/vendor/netlify.js.map +++ b/packages/expo-server/build/mjs/vendor/netlify.js.map @@ -1 +1 @@ -{"version":3,"file":"netlify.js","sourceRoot":"","sources":["../../../src/vendor/netlify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AASlD,yFAAyF;AACzF,SAAS,UAAU;IACjB,MAAM,UAAU,GAEZ,UAAU,CAAC;IACf,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iDAAiD;YAC/C,gEAAgE;YAChE,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAClF,mCAAmC;AACnC,MAAM,KAAK,GAAoB;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;IACzC,GAAG,CAAC,KAAU,EAAE,MAA+B,EAAE,GAAG,IAAW;QAC7D,UAAU,EAAE,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,OAAwB,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM;QACtF,WAAW,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;QAC9D,SAAS,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,SAAS;KAC/C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAoB,EAAE,EAAE;QAClD,IAAI,mBAAmB,IAAI,GAAG,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC3E,wFAAwF,CAC3F,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file +{"version":3,"file":"netlify.js","sourceRoot":"","sources":["../../../src/vendor/netlify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;AASlD,yFAAyF;AACzF,SAAS,UAAU;IACjB,MAAM,UAAU,GAEZ,UAAU,CAAC;IACf,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,iDAAiD;YAC/C,gEAAgE;YAChE,wFAAwF,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED,kFAAkF;AAClF,mCAAmC;AACnC,MAAM,KAAK,GAAoB;IAC7B,QAAQ,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,WAAW,CAAC;IACzC,GAAG,CAAC,KAAU,EAAE,MAA+B,EAAE,GAAG,IAAW;QAC7D,UAAU,EAAE,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC;QAClC,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,MAAyB;IAC5D,MAAM,mBAAmB,GAAG,CAAC,OAAgB,EAAE,OAAwB,EAAE,EAAE,CAAC,CAAC;QAC3E,MAAM,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;QACpF,WAAW,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,IAAI,IAAI;QAC9D,SAAS,EAAE,CAAC,OAAO,IAAI,UAAU,EAAE,CAAC,CAAC,SAAS;KAC/C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,iBAAiB,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAoB,EAAE,EAAE;QAClD,IAAI,mBAAmB,IAAI,GAAG,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,6EAA6E;gBAC3E,wFAAwF,CAC3F,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/vercel.js b/packages/expo-server/build/mjs/vendor/vercel.js index 460cb7f79042ee..6d1b7272908262 100644 --- a/packages/expo-server/build/mjs/vendor/vercel.js +++ b/packages/expo-server/build/mjs/vendor/vercel.js @@ -30,7 +30,7 @@ export function createRequestHandler(params) { const host = request.headers.get('host'); const proto = request.headers.get('x-forwarded-proto') || 'https'; return { - origin: host ? `${proto}://${host}` : 'null', + origin: host ? `${proto}://${host}` : null, // See: https://github.com/vercel/vercel/blob/b189b39/packages/functions/src/get-env.ts#L25C3-L25C13 environment: process.env.VERCEL_ENV ?? process.env.NODE_ENV, waitUntil: getContext().waitUntil, diff --git a/packages/expo-server/build/mjs/vendor/vercel.js.map b/packages/expo-server/build/mjs/vendor/vercel.js.map index ac3fb344c1ca62..cbe4403958638a 100644 --- a/packages/expo-server/build/mjs/vendor/vercel.js.map +++ b/packages/expo-server/build/mjs/vendor/vercel.js.map @@ -1 +1 @@ -{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../src/vendor/vercel.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../../src/vendor/vercel.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/workerd.d.ts b/packages/expo-server/build/mjs/vendor/workerd.d.ts index 3e9bf7a1bdcf0b..5fc08b17c6f430 100644 --- a/packages/expo-server/build/mjs/vendor/workerd.d.ts +++ b/packages/expo-server/build/mjs/vendor/workerd.d.ts @@ -1,7 +1,10 @@ import { type RequestHandlerParams } from './abstract'; import { ExecutionContext } from './environment/workerd'; export { ExpoError } from './abstract'; -export type RequestHandler = (req: Request, env: Env, ctx: ExecutionContext) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} /** * Returns a request handler for Workerd deployments. */ diff --git a/packages/expo-server/build/mjs/vendor/workerd.js b/packages/expo-server/build/mjs/vendor/workerd.js index bc013841bfd331..4ac57f776d8812 100644 --- a/packages/expo-server/build/mjs/vendor/workerd.js +++ b/packages/expo-server/build/mjs/vendor/workerd.js @@ -8,10 +8,12 @@ const STORE = new AsyncLocalStorage(); */ export function createRequestHandler(params, setup) { const run = createWorkerdRequestScope(STORE, params); - const onRequest = createExpoHandler({ - ...createWorkerdEnv(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = createWorkerdEnv(params); + const onRequest = createExpoHandler({ ...common, ...setup }); + function handler(request, env, ctx) { + return run(onRequest, request, env, ctx); + } + handler.preload = common.preload; + return handler; } //# sourceMappingURL=workerd.js.map \ No newline at end of file diff --git a/packages/expo-server/build/mjs/vendor/workerd.js.map b/packages/expo-server/build/mjs/vendor/workerd.js.map index 4ae8e215fe1dce..4531d2365bae26 100644 --- a/packages/expo-server/build/mjs/vendor/workerd.js.map +++ b/packages/expo-server/build/mjs/vendor/workerd.js.map @@ -1 +1 @@ -{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../src/vendor/workerd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAA6B,MAAM,YAAY,CAAC;AAClG,OAAO,EACL,gBAAgB,EAChB,yBAAyB,GAE1B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQvC,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAsD,EACtD,KAA4B;IAE5B,MAAM,GAAG,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,SAAS,GAAG,iBAAiB,CAAC;QAClC,GAAG,gBAAgB,CAAC,MAAM,CAAC;QAC3B,GAAG,KAAK;KACT,CAAC,CAAC;IACH,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC"} \ No newline at end of file +{"version":3,"file":"workerd.js","sourceRoot":"","sources":["../../../src/vendor/workerd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,oBAAoB,IAAI,iBAAiB,EAA6B,MAAM,YAAY,CAAC;AAClG,OAAO,EACL,gBAAgB,EAChB,yBAAyB,GAE1B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC,MAAM,KAAK,GAAG,IAAI,iBAAiB,EAAE,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAsD,EACtD,KAA4B;IAE5B,MAAM,GAAG,GAAG,yBAAyB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,iBAAiB,CAAC,EAAE,GAAG,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAE7D,SAAS,OAAO,CAAC,OAAgB,EAAE,GAAQ,EAAE,GAAqB;QAChE,OAAO,GAAG,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC"} \ No newline at end of file diff --git a/packages/expo-server/src/runtime/api.ts b/packages/expo-server/src/runtime/api.ts index 4f5047076a2175..3ccec9add865e6 100644 --- a/packages/expo-server/src/runtime/api.ts +++ b/packages/expo-server/src/runtime/api.ts @@ -25,10 +25,11 @@ function assertSupport(name: string, v: T | undefined): T { export { StatusError } from './error'; -/** Returns the current request's origin URL. +/** Returns the current request's URL. * - * This typically returns the request's `Origin` header, which contains the - * request origin URL or defaults to `null`. + * This typically returns the request's URL, or on certain platform, + * the origin of the request. This does not use the `Origin` header + * in development as it may contain an untrusted value. * @returns A request origin */ export function origin(): string | null { diff --git a/packages/expo-server/src/runtime/index.ts b/packages/expo-server/src/runtime/index.ts index d9f246b83a658e..497ebac224dc79 100644 --- a/packages/expo-server/src/runtime/index.ts +++ b/packages/expo-server/src/runtime/index.ts @@ -3,7 +3,7 @@ import { type ScopeDefinition, type RequestAPI, scopeRef, UpdateResponseHeaders import { importMetaRegistry } from '../utils/importMetaRegistry'; export interface RequestAPISetup extends RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; @@ -15,7 +15,9 @@ function setupRuntime() { enumerable: true, configurable: true, get() { - return scopeRef.current?.getStore()?.origin || 'null'; + // NOTE(@kitten): By convention, this property must be a string, and runtimes typically + // choose to stringify "null" when the value is not available + return scopeRef.current?.getStore()?.origin ?? 'null'; }, }); } catch {} diff --git a/packages/expo-server/src/runtime/scope.ts b/packages/expo-server/src/runtime/scope.ts index 7d85059fd6f49b..557139e87b4fc3 100644 --- a/packages/expo-server/src/runtime/scope.ts +++ b/packages/expo-server/src/runtime/scope.ts @@ -4,7 +4,7 @@ export type UpdateResponseHeaders = | ((headers: Headers) => Headers | void); export interface RequestAPI { - origin?: string; + origin?: string | null; environment?: string | null; requestHeaders?: Headers; waitUntil?(promise: Promise): void; diff --git a/packages/expo-server/src/vendor/eas.ts b/packages/expo-server/src/vendor/eas.ts index b0337d3180eb62..2c35dbbdcb0bad 100644 --- a/packages/expo-server/src/vendor/eas.ts +++ b/packages/expo-server/src/vendor/eas.ts @@ -6,11 +6,10 @@ import { createWorkerdEnv, ExecutionContext } from './environment/workerd'; export { ExpoError } from './abstract'; -export type RequestHandler = ( - req: Request, - env: Env, - ctx: ExecutionContext -) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} const STORE = new AsyncLocalStorage(); @@ -22,14 +21,18 @@ export function createRequestHandler( setup?: RequestHandlerParams ): RequestHandler { const makeRequestAPISetup = (request: Request, _env: Env, ctx: ExecutionContext) => ({ - origin: request.headers.get('Origin') || 'null', + origin: request.headers.get('Origin') || null, environment: request.headers.get('eas-environment') || null, waitUntil: ctx.waitUntil?.bind(ctx), }); const run = createRequestScope(STORE, makeRequestAPISetup); - const onRequest = createExpoHandler({ - ...createWorkerdEnv(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = createWorkerdEnv(params); + const onRequest = createExpoHandler({ ...common, ...setup }); + + function handler(request: Request, env: Env, ctx: ExecutionContext) { + return run(onRequest, request, env, ctx); + } + + handler.preload = common.preload; + return handler; } diff --git a/packages/expo-server/src/vendor/environment/common.ts b/packages/expo-server/src/vendor/environment/common.ts index 0b6d940ca2c3a1..28af55213542ec 100644 --- a/packages/expo-server/src/vendor/environment/common.ts +++ b/packages/expo-server/src/vendor/environment/common.ts @@ -6,26 +6,31 @@ import { isResponse, parseParams, resolveLoaderContextKey } from '../../utils/ma function initManifestRegExp(manifest: RawManifest): Manifest { return { ...manifest, - htmlRoutes: manifest.htmlRoutes.map((route) => ({ - ...route, - namedRegex: new RegExp(route.namedRegex), - })), - apiRoutes: manifest.apiRoutes.map((route) => ({ - ...route, - namedRegex: new RegExp(route.namedRegex), - })), - notFoundRoutes: manifest.notFoundRoutes.map((route) => ({ - ...route, - namedRegex: new RegExp(route.namedRegex), - })), - redirects: manifest.redirects?.map((route) => ({ - ...route, - namedRegex: new RegExp(route.namedRegex), - })), - rewrites: manifest.rewrites?.map((route) => ({ - ...route, - namedRegex: new RegExp(route.namedRegex), - })), + htmlRoutes: + manifest.htmlRoutes?.map((route) => ({ + ...route, + namedRegex: new RegExp(route.namedRegex), + })) ?? [], + apiRoutes: + manifest.apiRoutes?.map((route) => ({ + ...route, + namedRegex: new RegExp(route.namedRegex), + })) ?? [], + notFoundRoutes: + manifest.notFoundRoutes?.map((route) => ({ + ...route, + namedRegex: new RegExp(route.namedRegex), + })) ?? [], + redirects: + manifest.redirects?.map((route) => ({ + ...route, + namedRegex: new RegExp(route.namedRegex), + })) ?? [], + rewrites: + manifest.rewrites?.map((route) => ({ + ...route, + namedRegex: new RegExp(route.namedRegex), + })) ?? [], }; } @@ -36,15 +41,24 @@ interface EnvironmentInput { isDevelopment: boolean; } -export function createEnvironment(input: EnvironmentInput) { +export interface CommonEnvironment { + getRoutesManifest(): Promise; + getHtml(request: Request, route: Route): Promise; + getApiRoute(route: Route): Promise; + getMiddleware(middleware: MiddlewareInfo): Promise; + getLoaderData(request: Request, route: Route): Promise; + preload(): Promise; +} + +export function createEnvironment(input: EnvironmentInput): CommonEnvironment { // Cached manifest and SSR renderer, initialized on first request - let cachedManifest: Manifest | null = null; + let cachedManifest: Manifest | null | undefined; let ssrRenderer: SsrRenderFn | null = null; - async function getCachedRoutesManifest(): Promise { - if (!cachedManifest || input.isDevelopment) { + async function getRoutesManifest(): Promise { + if (cachedManifest === undefined || input.isDevelopment) { const json = await input.readJson('_expo/routes.json'); - cachedManifest = initManifestRegExp(json as RawManifest); + cachedManifest = json ? initManifestRegExp(json as RawManifest) : null; } return cachedManifest; } @@ -54,8 +68,8 @@ export function createEnvironment(input: EnvironmentInput) { return ssrRenderer; } - const manifest = await getCachedRoutesManifest(); - if (manifest.rendering?.mode !== 'ssr') { + const manifest = await getRoutesManifest(); + if (manifest?.rendering?.mode !== 'ssr') { return null; } @@ -100,11 +114,9 @@ export function createEnvironment(input: EnvironmentInput) { } return { - async getRoutesManifest(): Promise { - return getCachedRoutesManifest(); - }, + getRoutesManifest, - async getHtml(request: Request, route: Route): Promise { + async getHtml(request, route) { // SSR path: Render at runtime if SSR module is available const renderer = await getServerRenderer(); if (renderer) { @@ -146,11 +158,11 @@ export function createEnvironment(input: EnvironmentInput) { return null; }, - async getApiRoute(route: Route): Promise { + async getApiRoute(route) { return input.loadModule(route.file); }, - async getMiddleware(middleware: MiddlewareInfo): Promise { + async getMiddleware(middleware) { const mod = (await input.loadModule(middleware.file)) as any; if (typeof mod?.default !== 'function') { return null; @@ -158,7 +170,7 @@ export function createEnvironment(input: EnvironmentInput) { return mod; }, - async getLoaderData(request: Request, route: Route): Promise { + async getLoaderData(request, route) { const params = parseParams(request, route); const result = await executeLoader(request, route, params); @@ -168,5 +180,22 @@ export function createEnvironment(input: EnvironmentInput) { return Response.json(result ?? null); }, + + async preload() { + if (input.isDevelopment) { + return; + } + const manifest = await getRoutesManifest(); + if (manifest) { + const requests: string[] = []; + if (manifest.middleware) requests.push(manifest.middleware.file); + if (manifest.rendering) requests.push(manifest.rendering.file); + for (const apiRoute of manifest.apiRoutes) requests.push(apiRoute.file); + for (const htmlRoute of manifest.htmlRoutes) { + if (htmlRoute.loader) requests.push(htmlRoute.loader); + } + await Promise.all(requests.map((request) => input.loadModule(request))); + } + }, }; } diff --git a/packages/expo-server/src/vendor/environment/node.ts b/packages/expo-server/src/vendor/environment/node.ts index 3f6a0d31dfa1ff..395af99bd27ae9 100644 --- a/packages/expo-server/src/vendor/environment/node.ts +++ b/packages/expo-server/src/vendor/environment/node.ts @@ -1,7 +1,7 @@ import fs from 'node:fs'; import path from 'node:path'; -import { createEnvironment } from './common'; +import { type CommonEnvironment, createEnvironment } from './common'; import { assertRuntimeFetchAPISupport } from '../../ImmutableRequest'; import { createRequestScope } from '../../runtime'; import type { ScopeDefinition } from '../../runtime/scope'; @@ -12,7 +12,7 @@ interface NodeEnvParams { isDevelopment?: boolean; } -export function createNodeEnv(params: NodeEnvParams) { +export function createNodeEnv(params: NodeEnvParams): CommonEnvironment { assertRuntimeFetchAPISupport(); async function readText(request: string) { @@ -51,10 +51,19 @@ export function createNodeEnv(params: NodeEnvParams) { }); } +const getRequestURLOrigin = (request: Request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } catch { + return null; + } +}; + export function createNodeRequestScope(scopeDefinition: ScopeDefinition, params: NodeEnvParams) { return createRequestScope(scopeDefinition, (request: Request) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? process.env.NODE_ENV, })); } diff --git a/packages/expo-server/src/vendor/environment/workerd.ts b/packages/expo-server/src/vendor/environment/workerd.ts index bb2615d9cd9013..29af86ecf908fc 100644 --- a/packages/expo-server/src/vendor/environment/workerd.ts +++ b/packages/expo-server/src/vendor/environment/workerd.ts @@ -1,4 +1,4 @@ -import { createEnvironment } from './common'; +import { type CommonEnvironment, createEnvironment } from './common'; import { createRequestScope } from '../../runtime'; import type { ScopeDefinition } from '../../runtime/scope'; @@ -28,7 +28,7 @@ interface WorkerdEnvParams { isDevelopment?: boolean; } -export function createWorkerdEnv(params: WorkerdEnvParams) { +export function createWorkerdEnv(params: WorkerdEnvParams): CommonEnvironment { const build = params.build || '.'; const importCached = createCachedImport(); @@ -72,13 +72,22 @@ export interface ExecutionContext { props?: any; } +const getRequestURLOrigin = (request: Request) => { + try { + // NOTE: We don't trust any headers on incoming requests in "raw" environments + return new URL(request.url).origin || null; + } catch { + return null; + } +}; + export function createWorkerdRequestScope( scopeDefinition: ScopeDefinition, params: WorkerdEnvParams ) { const makeRequestAPISetup = (request: Request, _env: Env, ctx: ExecutionContext) => ({ requestHeaders: request.headers, - origin: request.headers.get('Origin') || 'null', + origin: getRequestURLOrigin(request), environment: params.environment ?? null, waitUntil: ctx.waitUntil?.bind(ctx), }); diff --git a/packages/expo-server/src/vendor/netlify.ts b/packages/expo-server/src/vendor/netlify.ts index ccb644a499f3d7..a17f7a89218582 100644 --- a/packages/expo-server/src/vendor/netlify.ts +++ b/packages/expo-server/src/vendor/netlify.ts @@ -41,7 +41,7 @@ const STORE: ScopeDefinition = { export function createRequestHandler(params: { build: string }) { const makeRequestAPISetup = (request: Request, context?: NetlifyContext) => ({ - origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || 'null', + origin: (context ?? getContext()).site?.url || request.headers.get('Origin') || null, environment: (context ?? getContext()).deploy?.context || null, waitUntil: (context ?? getContext()).waitUntil, }); diff --git a/packages/expo-server/src/vendor/vercel.ts b/packages/expo-server/src/vendor/vercel.ts index 0324217e2b3a3c..79a665b3fdcc48 100644 --- a/packages/expo-server/src/vendor/vercel.ts +++ b/packages/expo-server/src/vendor/vercel.ts @@ -52,7 +52,7 @@ export function createRequestHandler(params: { build: string }): RequestHandler const host = request.headers.get('host'); const proto = request.headers.get('x-forwarded-proto') || 'https'; return { - origin: host ? `${proto}://${host}` : 'null', + origin: host ? `${proto}://${host}` : null, // See: https://github.com/vercel/vercel/blob/b189b39/packages/functions/src/get-env.ts#L25C3-L25C13 environment: process.env.VERCEL_ENV ?? process.env.NODE_ENV, waitUntil: getContext().waitUntil, diff --git a/packages/expo-server/src/vendor/workerd.ts b/packages/expo-server/src/vendor/workerd.ts index 441c03341ddec2..a676d27a0fd07f 100644 --- a/packages/expo-server/src/vendor/workerd.ts +++ b/packages/expo-server/src/vendor/workerd.ts @@ -9,11 +9,10 @@ import { export { ExpoError } from './abstract'; -export type RequestHandler = ( - req: Request, - env: Env, - ctx: ExecutionContext -) => Promise; +export interface RequestHandler { + (req: Request, env: Env, ctx: ExecutionContext): Promise; + preload(): Promise; +} const STORE = new AsyncLocalStorage(); @@ -25,9 +24,13 @@ export function createRequestHandler( setup?: RequestHandlerParams ): RequestHandler { const run = createWorkerdRequestScope(STORE, params); - const onRequest = createExpoHandler({ - ...createWorkerdEnv(params), - ...setup, - }); - return (request, env, ctx) => run(onRequest, request, env, ctx); + const common = createWorkerdEnv(params); + const onRequest = createExpoHandler({ ...common, ...setup }); + + function handler(request: Request, env: Env, ctx: ExecutionContext) { + return run(onRequest, request, env, ctx); + } + + handler.preload = common.preload; + return handler; } diff --git a/packages/expo-ui/CHANGELOG.md b/packages/expo-ui/CHANGELOG.md index 8f9303e754f6c5..e3c40f2cb0546e 100644 --- a/packages/expo-ui/CHANGELOG.md +++ b/packages/expo-ui/CHANGELOG.md @@ -12,6 +12,7 @@ ### ๐Ÿ› Bug fixes +- [iOS] Fix `clipShape` and `mask` modifiers silently falling through to `Rectangle()` for `capsule` and `ellipse` shapes. ([#43158](https://github.com/expo/expo/pull/43158) by [@ramonclaudio](https://github.com/ramonclaudio)) - [iOS] Fix rendering `0` in SwiftUI Text. ([#43036](https://github.com/expo/expo/pull/43036) by [@jakex7](https://github.com/jakex7)) - [iOS] Set initial state in `init` instead of `onAppear` in `DatePicker`, `Section`, `DisclosureGroup`, `Popover`, and `ColorPicker` components. ([#42933](https://github.com/expo/expo/pull/42933) by [@nishan](https://github.com/intergalacticspacehighway)) diff --git a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts index 73a0348a72ae48..7bfa41a1b38cf3 100644 --- a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts +++ b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts @@ -147,7 +147,7 @@ export declare const opacity: (value: number) => ModifierConfig; * @param cornerRadius - Corner radius for rounded rectangle (default: 8) * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipshape(_:style:)). */ -export declare const clipShape: (shape: "rectangle" | "circle" | "roundedRectangle", cornerRadius?: number) => ModifierConfig; +export declare const clipShape: (shape: "rectangle" | "circle" | "capsule" | "ellipse" | "roundedRectangle", cornerRadius?: number) => ModifierConfig; /** * Adds a border to a view. * @param params - The border parameters. Color and width. @@ -484,7 +484,7 @@ export declare const layoutPriority: (priority: number) => ModifierConfig; * @param cornerRadius - Corner radius for rounded rectangle (default: `8`). * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/mask(_:)). */ -export declare const mask: (shape: "rectangle" | "circle" | "roundedRectangle", cornerRadius?: number) => ModifierConfig; +export declare const mask: (shape: "rectangle" | "circle" | "capsule" | "ellipse" | "roundedRectangle", cornerRadius?: number) => ModifierConfig; /** * Overlays another view on top. * @param params - Overlay color and alignment. diff --git a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts.map b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts.map index ad08f2e220c287..1486fee31fef60 100644 --- a/packages/expo-ui/build/swift-ui/modifiers/index.d.ts.map +++ b/packages/expo-ui/build/swift-ui/modifiers/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/swift-ui/modifiers/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/swift-ui/modifiers/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/expo-ui/ios/Modifiers/ViewModifierRegistry.swift b/packages/expo-ui/ios/Modifiers/ViewModifierRegistry.swift index 9cc312458c0c3b..90fe9aeedca39d 100644 --- a/packages/expo-ui/ios/Modifiers/ViewModifierRegistry.swift +++ b/packages/expo-ui/ios/Modifiers/ViewModifierRegistry.swift @@ -373,18 +373,24 @@ internal struct BorderModifier: ViewModifier, Record { } internal struct ClipShapeModifier: ViewModifier, Record { - @Field var shape: String = "rectangle" + @Field var shape: ShapeType = .rectangle @Field var cornerRadius: CGFloat = 8 + @Field var roundedCornerStyle: RoundedCornerStyle? + @Field var cornerSize: CornerSize? @ViewBuilder func body(content: Content) -> some View { switch shape { - case "circle": + case .capsule: + content.clipShape(makeCapsule(style: roundedCornerStyle)) + case .circle: content.clipShape(Circle()) - case "roundedRectangle": - content.clipShape(RoundedRectangle(cornerRadius: cornerRadius)) - default: + case .ellipse: + content.clipShape(Ellipse()) + case .rectangle: content.clipShape(Rectangle()) + case .roundedRectangle: + content.clipShape(makeRoundedRectangle(cornerRadius: cornerRadius, cornerSize: cornerSize, style: roundedCornerStyle)) } } } @@ -587,18 +593,24 @@ internal struct ClippedModifier: ViewModifier, Record { } internal struct MaskModifier: ViewModifier, Record { - @Field var shape: String = "rectangle" + @Field var shape: ShapeType = .rectangle @Field var cornerRadius: CGFloat = 8 + @Field var roundedCornerStyle: RoundedCornerStyle? + @Field var cornerSize: CornerSize? @ViewBuilder func body(content: Content) -> some View { switch shape { - case "circle": + case .capsule: + content.mask(makeCapsule(style: roundedCornerStyle)) + case .circle: content.mask(Circle()) - case "roundedRectangle": - content.mask(RoundedRectangle(cornerRadius: cornerRadius)) - default: + case .ellipse: + content.mask(Ellipse()) + case .rectangle: content.mask(Rectangle()) + case .roundedRectangle: + content.mask(makeRoundedRectangle(cornerRadius: cornerRadius, cornerSize: cornerSize, style: roundedCornerStyle)) } } } diff --git a/packages/expo-ui/src/swift-ui/modifiers/index.ts b/packages/expo-ui/src/swift-ui/modifiers/index.ts index eef3c267815353..78e5d13136f489 100644 --- a/packages/expo-ui/src/swift-ui/modifiers/index.ts +++ b/packages/expo-ui/src/swift-ui/modifiers/index.ts @@ -211,7 +211,7 @@ export const opacity = (value: number) => createModifier('opacity', { value }); * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/clipshape(_:style:)). */ export const clipShape = ( - shape: 'rectangle' | 'circle' | 'roundedRectangle', + shape: 'rectangle' | 'circle' | 'capsule' | 'ellipse' | 'roundedRectangle', cornerRadius?: number ) => createModifier('clipShape', { shape, cornerRadius }); @@ -600,8 +600,10 @@ export const layoutPriority = (priority: number) => createModifier('layoutPriori * @param cornerRadius - Corner radius for rounded rectangle (default: `8`). * @see Official [SwiftUI documentation](https://developer.apple.com/documentation/swiftui/view/mask(_:)). */ -export const mask = (shape: 'rectangle' | 'circle' | 'roundedRectangle', cornerRadius?: number) => - createModifier('mask', { shape, cornerRadius }); +export const mask = ( + shape: 'rectangle' | 'circle' | 'capsule' | 'ellipse' | 'roundedRectangle', + cornerRadius?: number +) => createModifier('mask', { shape, cornerRadius }); /** * Overlays another view on top. diff --git a/packages/expo-widgets/CHANGELOG.md b/packages/expo-widgets/CHANGELOG.md index 34f3def80a7d14..077336036ea66c 100644 --- a/packages/expo-widgets/CHANGELOG.md +++ b/packages/expo-widgets/CHANGELOG.md @@ -7,6 +7,7 @@ ### ๐ŸŽ‰ New features - Render widgets in JSC. ([#42987](https://github.com/expo/expo/pull/42987) by [@jakex7](https://github.com/jakex7)) +- Create widgets runtime bundle at build time. ([#43170](https://github.com/expo/expo/pull/43170) by [@jakex7](https://github.com/jakex7)) ### ๐Ÿ› Bug fixes diff --git a/packages/expo-widgets/app.json b/packages/expo-widgets/app.json new file mode 100644 index 00000000000000..a1f1bded1568db --- /dev/null +++ b/packages/expo-widgets/app.json @@ -0,0 +1,14 @@ +{ + "expo": { + "name": "ExpoWidgets", + "slug": "expo-widgets", + "web": { + "output": "single" + }, + "experiments": { + "reactCompiler": false, + "autolinkingModuleResolution": true, + "baseUrl": "./bundle/" + } + } +} diff --git a/packages/expo-widgets/bundle/.gitignore b/packages/expo-widgets/bundle/.gitignore new file mode 100644 index 00000000000000..567609b1234a9b --- /dev/null +++ b/packages/expo-widgets/bundle/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/packages/expo-widgets/bundle/expo-module-stub.ts b/packages/expo-widgets/bundle/expo-module-stub.ts new file mode 100644 index 00000000000000..e9ea4dd2c34398 --- /dev/null +++ b/packages/expo-widgets/bundle/expo-module-stub.ts @@ -0,0 +1,15 @@ +export function requireNativeModule(name: string) { + return {}; +} + +export function requireNativeView(moduleName: string, viewName: string) { + const wrapper = { + [viewName]: (props?: Record) => { + return { + type: viewName, + props: props || {}, + }; + }, + }; + return wrapper[viewName] as unknown as React.ComponentType; +} diff --git a/packages/expo-widgets/bundle/index.ts b/packages/expo-widgets/bundle/index.ts new file mode 100644 index 00000000000000..2de664726be82b --- /dev/null +++ b/packages/expo-widgets/bundle/index.ts @@ -0,0 +1,70 @@ +/* eslint-disable no-var */ + +import * as swiftUI from '@expo/ui/swift-ui'; +import * as modifiers from '@expo/ui/swift-ui/modifiers'; + +import * as jsxRuntime from './jsx-runtime-stub'; +import * as React from './react-stub'; + +type WidgetProps = Record; +type WidgetNode = { props?: WidgetProps }; + +declare global { + var __expoWidgetLayout: (props: WidgetProps) => WidgetNode; + var __expoWidgetProps: WidgetProps | undefined; + var __expoWidgetRender: (timestamp: number, family?: string) => WidgetProps; + var __expoWidgetHandlePress: ( + timestamp: number, + family: string | undefined, + target: string | undefined + ) => WidgetProps | undefined; +} + +const __expoWidgetRender = function (timestamp: number, family?: string) { + if (family) { + return globalThis.__expoWidgetLayout( + Object.assign({ date: new Date(timestamp), family }, globalThis.__expoWidgetProps || {}) + ); + } + return globalThis.__expoWidgetLayout( + Object.assign({ date: new Date(timestamp) }, globalThis.__expoWidgetProps || {}) + ); +}; + +const __expoWidgetHandlePress = function ( + timestamp: number, + family: string | undefined, + target: string | undefined +) { + function findAndCallOnPress(node?: WidgetNode): WidgetProps | undefined { + const props = node?.props as { + onButtonPress?: () => WidgetProps; + target?: string; + children?: unknown; + }; + if (props?.onButtonPress && props?.target === target) { + return props.onButtonPress(); + } + + if (props?.children && Array.isArray(props.children)) { + for (const child of props.children) { + const result = findAndCallOnPress(child as WidgetNode); + if (result) { + return result; + } + } + } + } + + const node = globalThis.__expoWidgetRender(timestamp, family); + return findAndCallOnPress(node as WidgetNode); +}; + +Object.assign(globalThis, { + ...swiftUI, + ...modifiers, + ...jsxRuntime, + ...React, + __expoWidgetRender, + __expoWidgetHandlePress, +}); diff --git a/packages/expo-widgets/bundle/jsx-runtime-stub.ts b/packages/expo-widgets/bundle/jsx-runtime-stub.ts new file mode 100644 index 00000000000000..ceaced05e873e8 --- /dev/null +++ b/packages/expo-widgets/bundle/jsx-runtime-stub.ts @@ -0,0 +1,57 @@ +export const REACT_ELEMENT_TYPE: symbol = Symbol.for('react.transitional.element'); +export const REACT_FRAGMENT_TYPE: symbol = Symbol.for('react.fragment'); + +function ReactElement(type: typeof ReactElement, key: string | null, props: Record) { + if (typeof type === 'function') { + return (type as any)(props); + } + + const element = { + type, + key, + props, + }; + + return element; +} + +function jsxProd(type: typeof ReactElement, config: any, maybeKey?: string | number | bigint) { + let key = null; + if (maybeKey !== undefined) { + key = '' + maybeKey; + } + if (hasValidKey(config)) { + key = '' + config.key; + } + + let props: Record; + if (!('key' in config)) { + props = config; + } else { + props = {}; + for (const propName in config) { + if (propName !== 'key') { + props[propName] = config[propName]; + } + } + } + + return ReactElement(type, key, props); +} + +function hasValidKey(config: any) { + return config.key !== undefined; +} + +const jsxFileName = 'widget'; +export { + REACT_FRAGMENT_TYPE as Fragment, + jsxFileName as _jsxFileName, + jsxProd, + jsxProd as jsx, + jsxProd as jsxs, + jsxProd as jsxDEV, + jsxProd as _jsx, + jsxProd as _jsxs, + jsxProd as _jsxDEV, +}; diff --git a/packages/expo-widgets/bundle/react-stub.ts b/packages/expo-widgets/bundle/react-stub.ts new file mode 100644 index 00000000000000..67e5563cf277b4 --- /dev/null +++ b/packages/expo-widgets/bundle/react-stub.ts @@ -0,0 +1,11 @@ +export const Children = { + toArray(children: unknown) { + if (children === undefined || children === null) { + return []; + } + return Array.isArray(children) ? children : [children]; + }, +}; +export const isValidElement = (value: unknown) => { + return Boolean(value) && typeof value === 'object' && 'type' in (value as object); +}; diff --git a/packages/expo-widgets/ios/ExpoWidgets.podspec b/packages/expo-widgets/ios/ExpoWidgets.podspec index 3363997cd2b28e..f9f9a04fbd36e9 100644 --- a/packages/expo-widgets/ios/ExpoWidgets.podspec +++ b/packages/expo-widgets/ios/ExpoWidgets.podspec @@ -32,4 +32,38 @@ Pod::Spec.new do |s| else s.source_files = "**/*.{h,m,swift}" end + + build_bundle_script = { + :name => 'Build ExpoWidgets Bundle', + :script => %Q{ + echo "Building ExpoWidgets.bundle..." + #{__dir__}/../scripts/with-node.sh #{__dir__}/../scripts/build-bundle.mjs + }, + :execution_position => :before_compile, + # NOTE(@krystofwoldrich): Ideally we would specify `__dir__/**/*`, but Xcode doesn't support patterns + :input_files => ["#{__dir__}/../package.json"], + :output_files => ["#{__dir__}/../bundle/build/ExpoWidgets.bundle"], + } + copy_bundle_script = { + :name => 'Prepare ExpoWidgets Resources', + :script => %Q{ + echo "Preparing ExpoWidgets.bundle..." + source="#{__dir__}/../bundle/build/ExpoWidgets.bundle" + dest="${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoWidgets.bundle" + echo "Copying ${source} to ${dest}" + cp "${source}" "${dest}" + }, + :execution_position => :before_compile, + :input_files => ["#{__dir__}/../bundle/build/ExpoWidgets.bundle"] + } + # :always_out_of_date is only available in CocoaPods 1.13.0 and later + if Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.13.0') + # always run the script without warning + copy_bundle_script[:always_out_of_date] = "1" + end + s.script_phases = [build_bundle_script, copy_bundle_script] + s.resource_bundles = { + 'ExpoWidgets' => [], + } + end diff --git a/packages/expo-widgets/ios/Widgets/WidgetContext.swift b/packages/expo-widgets/ios/Widgets/WidgetContext.swift index 46d3781068fa58..ba4110dcebfb4f 100644 --- a/packages/expo-widgets/ios/Widgets/WidgetContext.swift +++ b/packages/expo-widgets/ios/Widgets/WidgetContext.swift @@ -13,7 +13,14 @@ func createWidgetContext(layout: String, props: [String: Any]) -> JSContext? { } // Inject ExpoUI bundle - context.evaluateScript(expoUIBundleJS) + guard let bundleURL = Bundle.main.url(forResource: "ExpoWidgets", withExtension: "bundle"), + let bundle = Bundle(url: bundleURL), + let url = bundle.url(forResource: "ExpoWidgets", withExtension: "bundle"), + let bundleJS = try? String(contentsOf: url, encoding: .utf8) else { + print("[ExpoWidgets] Missing ExpoWidgets.bundle") + return nil + } + context.evaluateScript(bundleJS) // Inject layout and props let layoutValue = context.evaluateScript("(\(layout))") @@ -21,4 +28,3 @@ func createWidgetContext(layout: String, props: [String: Any]) -> JSContext? { context.setObject(props, forKeyedSubscript: "__expoWidgetProps" as NSString) return context } - diff --git a/packages/expo-widgets/ios/Widgets/expo-ui.bundle.swift b/packages/expo-widgets/ios/Widgets/expo-ui.bundle.swift deleted file mode 100644 index 4eb6108a78c544..00000000000000 --- a/packages/expo-widgets/ios/Widgets/expo-ui.bundle.swift +++ /dev/null @@ -1,69 +0,0 @@ -let expoUIBundleJS = """ -var __BUNDLE_START_TIME__=globalThis.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=false,process=globalThis.process||{},__METRO_GLOBAL_PREFIX__='';process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"production"; -!(function(e){"use strict";e.__r=i,e[`${__METRO_GLOBAL_PREFIX__}__d`]=function(e,n,o){if(t.has(n))return;const i={dependencyMap:o,factory:e,hasError:!1,importedAll:r,importedDefault:r,isInitialized:!1,publicModule:{exports:{}}};t.set(n,i)},e.__c=o,e.__registerSegment=function(e,r,n){p[e]=r,n&&n.forEach(r=>{t.has(r)||h.has(r)||h.set(r,e)})};var t=o();const r={},{hasOwnProperty:n}={};function o(){return t=new Map}function i(e,r){if(null===e)throw new Error("Cannot find module");const n=e,o=t.get(n);return o&&o.isInitialized?o.publicModule.exports:d(n,o)}function l(e){const n=e,o=t.get(n);if(o&&o.importedDefault!==r)return o.importedDefault;const l=i(n),u=l&&l.__esModule?l.default:l;return t.get(n).importedDefault=u}function u(e){const o=e,l=t.get(o);if(l&&l.importedAll!==r)return l.importedAll;const u=i(o);let c;if(u&&u.__esModule)c=u;else{if(c={},u)for(const e in u)n.call(u,e)&&(c[e]=u[e]);c.default=u}return t.get(o).importedAll=c}i.importDefault=l,i.importAll=u,i.context=function(){throw new Error("The experimental Metro feature `require.context` is not enabled in your project.")},i.resolveWeak=function(){throw new Error("require.resolveWeak cannot be called dynamically.")};let c=!1;function d(t,r){if(!c&&e.ErrorUtils){let n;c=!0;try{n=g(t,r)}catch(t){e.ErrorUtils.reportFatalError(t)}return c=!1,n}return g(t,r)}const a=16,s=65535;function f(e){return{segmentId:e>>>a,localId:e&s}}i.unpackModuleId=f,i.packModuleId=function(e){return(e.segmentId<0){const e=h.get(r)??0,o=p[e];null!=o&&(o(r),n=t.get(r),h.delete(r))}const o=e.nativeRequire;if(!n&&o){const{segmentId:e,localId:i}=f(r);o(i,e),n=t.get(r)}if(!n)throw m(r);if(n.hasError)throw n.error;n.isInitialized=!0;const{factory:c,dependencyMap:d}=n;try{const t=n.publicModule;return t.id=r,c(e,i,l,u,t,t.exports,d),n.factory=void 0,n.dependencyMap=void 0,t.exports}catch(e){throw n.hasError=!0,n.error=e,n.isInitialized=!1,n.publicModule.exports=void 0,e}}function m(e){return Error('Requiring unknown module "'+e+'".')}})('undefined'!=typeof globalThis?globalThis:'undefined'!=typeof global?global:'undefined'!=typeof window?window:this); -__d(function(g,r,_i,a,_m,e,d){"use strict";var t,n=this&&this.__createBinding||(Object.create?function(t,n,i,o){void 0===o&&(o=i);var s=Object.getOwnPropertyDescriptor(n,i);s&&!("get"in s?!n.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return n[i]}}),Object.defineProperty(t,o,s)}:function(t,n,i,o){void 0===o&&(o=i),t[o]=n[i]}),i=this&&this.__setModuleDefault||(Object.create?function(t,n){Object.defineProperty(t,"default",{enumerable:!0,value:n})}:function(t,n){t.default=n}),o=this&&this.__importStar||(t=function(n){return t=Object.getOwnPropertyNames||function(t){var n=[];for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(n[n.length]=i);return n},t(n)},function(o){if(o&&o.__esModule)return o;var s={};if(null!=o)for(var u=t(o),l=0;l{t?.onIsPresentedChange?.(n)}})}},2,[3,4,5,6,7]); -__d(function(g,r,i,a,m,_e,d){m.exports=function(e){return e&&e.__esModule?e:{default:e}},m.exports.__esModule=!0,m.exports.default=m.exports},3,[]); -__d(function(g,_r,i,a,m,_e,d){m.exports=function(r,e){if(null==r)return{};var n={};for(var t in r)if({}.hasOwnProperty.call(r,t)){if(e.includes(t))continue;n[t]=r[t]}return n},m.exports.__esModule=!0,m.exports.default=m.exports},4,[]); -__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.requireNativeModule=function(t){return{}},e.requireNativeView=function(t,u){return{[u]:t=>({type:u,props:t||{}})}[u]}},5,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.createViewModifierEventListener=function(t){const n={};for(const o of t)o.eventListener&&(n[o.$type]=o.eventListener);return{onGlobalEvent:({nativeEvent:t})=>{for(const[o,c]of Object.entries(t)){const t=n[o];t&&t(c)}}}}},6,[]); -__d(function(g,r,i,a,m,e,d){"use strict";function t(t,n,E){if('function'==typeof t)return t(E);return{type:t,key:n,props:E}}function n(n,o,_){let s,T=null;if(void 0!==_&&(T=''+_),E(o)&&(T=''+o.key),'key'in o){s={};for(const t in o)'key'!==t&&(s[t]=o[t])}else s=o;return t(n,T,s)}function E(t){return void 0!==t.key}Object.defineProperty(e,"__esModule",{value:!0}),e._jsxFileName=e.Fragment=e.REACT_FRAGMENT_TYPE=e.REACT_ELEMENT_TYPE=void 0,e.jsxProd=n,e.jsx=n,e.jsxs=n,e.jsxDEV=n,e._jsx=n,e._jsxs=n,e._jsxDEV=n,e.REACT_ELEMENT_TYPE=Symbol.for('react.transitional.element'),e.REACT_FRAGMENT_TYPE=Symbol.for('react.fragment'),e.Fragment=e.REACT_FRAGMENT_TYPE;e._jsxFileName='widget'},7,[]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Button=function(n){const{label:o,children:f,onPress:b,modifiers:v}=n,j=(0,t.default)(n,c),P=Object.assign({},j,{modifiers:v},v?(0,s.createViewModifierEventListener)(v):void 0,{onButtonPress:b});return(0,l.jsx)(u,Object.assign({},P,{label:o,children:f}))};var t=n(r(d[1])),o=r(d[2]),s=r(d[3]),l=r(d[4]);const c=["label","children","onPress","modifiers"],u=(0,o.requireNativeView)('ExpoUI','Button')},8,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Chart=function(t){let{data:s,modifiers:v,referenceLines:l}=t,L=(0,n.default)(t,c);return(0,o.jsx)(u,Object.assign({data:s,referenceLines:l,modifiers:v},v?(0,f.createViewModifierEventListener)(v):void 0,L))};var n=t(r(d[1])),s=r(d[2]),f=r(d[3]),o=r(d[4]);const c=["style","data","modifiers","referenceLines"],u=(0,s.requireNativeView)('ExpoUI','ChartView')},9,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ColorPicker=function(n){let{selection:t,onSelectionChange:C,modifiers:_}=n,b=(0,o.default)(n,f);const h=(0,c.useCallback)(n=>{C?.(n.nativeEvent.value)},[C]);return(0,u.jsx)(v,Object.assign({modifiers:_},_?(0,s.createViewModifierEventListener)(_):void 0,{selection:(0,l.default)(t||''),onSelectionChange:h},b))};var o=n(r(d[1])),t=r(d[2]),c=r(d[3]),l=n(r(d[4])),s=r(d[5]),u=r(d[6]);const f=["selection","onSelectionChange","modifiers"],v=(0,t.requireNativeView)('ExpoUI','ColorPickerView')},10,[3,4,5,11,12,6,7]); -__d(function(g,r,i,a,m,e,d){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.isValidElement=e.Children=void 0,e.Children={toArray:l=>null==l?[]:Array.isArray(l)?l:[l]};e.isValidElement=l=>Boolean(l)&&'object'==typeof l&&'type'in l},11,[]); -__d(function(g,r,i,a,m,e,d){},12,[]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ContentUnavailableView=function(n){return(0,c.jsx)(u,Object.assign({},v(n)))};var t=n(r(d[1])),o=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,o.requireNativeView)('ExpoUI','ContentUnavailableView');function v(n){const{modifiers:o}=n,c=(0,t.default)(n,f);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,c)}},13,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.ContextMenu=w,e.Items=c,e.Preview=j,e.Trigger=v;var t=r(d[0]),n=r(d[1]);const u=(0,t.requireNativeView)('ExpoUI','ContextMenu'),o=(0,t.requireNativeView)('ExpoUI','ContextMenuActivationElement'),s=(0,t.requireNativeView)('ExpoUI','ContextMenuPreview'),x=(0,t.requireNativeView)('ExpoUI','ContextMenuContent');function c(t){return(0,n.jsx)(x,Object.assign({},t))}function v(t){return(0,n.jsx)(o,Object.assign({},t))}function j(t){return(0,n.jsx)(s,Object.assign({},t))}function w(t){return(0,n.jsx)(u,Object.assign({},t))}w.Trigger=v,w.Preview=j,w.Items=c},14,[5,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.DatePicker=function(t){return(0,c.jsx)(u,Object.assign({},f(t)))};var n=t(r(d[1])),o=r(d[2]),s=r(d[3]),c=r(d[4]);const v=["modifiers","onDateChange","selection","range"];function f(t){const{modifiers:o,onDateChange:c,selection:f,range:u}=t,l=(0,n.default)(t,v);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,l,{selection:f?.toISOString(),range:u?{start:u.start?.toISOString(),end:u.end?.toISOString()}:void 0,onDateChange:c?({nativeEvent:{date:t}})=>{c(new Date(t))}:void 0})}const u=(0,o.requireNativeView)('ExpoUI','DatePickerView')},15,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.Divider=function(n){return(0,t.jsx)(o,Object.assign({},n))};var n=r(d[0]),t=r(d[1]);const o=(0,n.requireNativeView)('ExpoUI','DividerView')},16,[5,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.DisclosureGroup=function(n){const{onIsExpandedChange:s,modifiers:p}=n,v=(0,o.default)(n,u);const E=Object.assign({modifiers:p},p?(0,t.createViewModifierEventListener)(p):void 0,v);return(0,c.jsx)(f,Object.assign({},E,{onIsExpandedChange:function(n){s?.(n.nativeEvent.isExpanded)}}))};var o=n(r(d[1])),s=r(d[2]),t=r(d[3]),c=r(d[4]);const u=["onIsExpandedChange","modifiers"],f=(0,s.requireNativeView)('ExpoUI','DisclosureGroupView')},17,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Form=function(t){return(0,c.jsx)(u,Object.assign({},v(t)))};var n=t(r(d[1])),o=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,o.requireNativeView)('ExpoUI','FormView');function v(t){const{modifiers:o}=t,c=(0,n.default)(t,f);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,c)}},18,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var u=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Gauge=function(u){const{modifiers:n,children:b,currentValueLabel:x,minimumValueLabel:f,maximumValueLabel:L}=u,h=(0,l.default)(u,s);return(0,t.jsxs)(V,Object.assign({modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0,h,{children:[b&&(0,t.jsx)(o,{kind:"label",children:b}),x&&(0,t.jsx)(o,{kind:"currentValue",children:x}),f&&(0,t.jsx)(o,{kind:"minimumValue",children:f}),L&&(0,t.jsx)(o,{kind:"maximumValue",children:L})]}))};var l=u(r(d[1])),n=r(d[2]),c=r(d[3]),t=r(d[4]);const s=["modifiers","children","currentValueLabel","minimumValueLabel","maximumValueLabel"],V=(0,n.requireNativeView)('ExpoUI','GaugeView'),o=(0,n.requireNativeView)('ExpoUI','GaugeLabelView')},19,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Host=function(t){const{matchContents:n,onLayoutContent:y,ignoreSafeArea:C,modifiers:h,layoutDirection:v}=t,L=(0,o.default)(t,u);return(0,f.jsx)(l,Object.assign({modifiers:h},h?(0,c.createViewModifierEventListener)(h):void 0,{matchContentsVertical:'object'==typeof n?n.vertical:n,matchContentsHorizontal:'object'==typeof n?n.horizontal:n,onLayoutContent:y,layoutDirection:v??(s.default.getConstants().isRTL?'rightToLeft':'leftToRight'),ignoreSafeArea:C},L))};var o=t(r(d[1])),n=r(d[2]),s=t(r(d[3])),c=r(d[4]),f=r(d[5]);const u=["matchContents","onLayoutContent","ignoreSafeArea","modifiers","layoutDirection"],l=(0,n.requireNativeView)('ExpoUI','HostView')},20,[3,4,5,12,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Image=function(n){return(0,u.jsx)(v,Object.assign({},f(n)))};var s=n(r(d[1])),t=r(d[2]),o=r(d[3]),u=r(d[4]);const c=["onPress","modifiers"];function f(n){const{onPress:t,modifiers:u}=n,f=(0,s.default)(n,c);return Object.assign({modifiers:u},u?(0,o.createViewModifierEventListener)(u):void 0,f,t?{useTapGesture:!0,onTap:()=>t()}:null)}const v=(0,t.requireNativeView)('ExpoUI','ImageView')},21,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Label=function(n){const{modifiers:t,icon:v}=n,b=(0,o.default)(n,f);return(0,s.jsx)(l,Object.assign({modifiers:t},t?(0,c.createViewModifierEventListener)(t):void 0,b,{children:v&&(0,s.jsx)(u,{children:v})}))};var o=n(r(d[1])),t=r(d[2]),c=r(d[3]),s=r(d[4]);const f=["modifiers","icon"],l=(0,t.requireNativeView)('ExpoUI','LabelView'),u=(0,t.requireNativeView)('ExpoUI','LabelIcon')},22,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.LabeledContent=function(n){const{modifiers:o,label:v,children:x}=n,L=(0,t.default)(n,c),h='string'==typeof v;return(0,s.jsxs)(b,Object.assign({modifiers:o,label:h?v:void 0},o?(0,l.createViewModifierEventListener)(o):void 0,L,{children:[v&&!h&&(0,s.jsx)(f,{children:v}),(0,s.jsx)(u,{children:x})]}))};var t=n(r(d[1])),o=r(d[2]),l=r(d[3]),s=r(d[4]);const c=["modifiers","label","children"],b=(0,o.requireNativeView)('ExpoUI','LabeledContentView'),f=(0,o.requireNativeView)('ExpoUI','LabeledContentLabel'),u=(0,o.requireNativeView)('ExpoUI','LabeledContentContent')},23,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.HStack=function(t){const{modifiers:n}=t,v=(0,o.default)(t,f);return(0,c.jsx)(u,Object.assign({modifiers:n},n?(0,s.createViewModifierEventListener)(n):void 0,v))};var o=t(r(d[1])),n=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,n.requireNativeView)('ExpoUI','HStackView')},24,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.VStack=function(t){const{modifiers:n}=t,v=(0,o.default)(t,f);return(0,c.jsx)(u,Object.assign({modifiers:n},n?(0,s.createViewModifierEventListener)(n):void 0,v))};var o=t(r(d[1])),n=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,n.requireNativeView)('ExpoUI','VStackView')},25,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ZStack=function(t){const{modifiers:n}=t,v=(0,o.default)(t,f);return(0,c.jsx)(u,Object.assign({modifiers:n},n?(0,s.createViewModifierEventListener)(n):void 0,v))};var o=t(r(d[1])),n=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,n.requireNativeView)('ExpoUI','ZStackView')},26,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var o=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Group=function(o){const{modifiers:n}=o,v=(0,t.default)(o,f);return(0,u.jsx)(c,Object.assign({modifiers:n},n?(0,s.createViewModifierEventListener)(n):void 0,v))};var t=o(r(d[1])),n=r(d[2]),s=r(d[3]),u=r(d[4]);const f=["modifiers"],c=(0,n.requireNativeView)('ExpoUI','GroupView')},27,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.List=E,Object.defineProperty(e,"ListForEach",{enumerable:!0,get:function(){return c.ListForEach}});var t=n(r(d[1])),o=r(d[2]),c=r(d[3]),s=r(d[4]),u=r(d[5]);const f=["modifiers"],l=["children"],h=(0,o.requireNativeView)('ExpoUI','ListView');function v(n){const{modifiers:o}=n,c=(0,t.default)(n,f);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,c,{onSelectionChange:({nativeEvent:{selection:t}})=>n?.onSelectionChange?.(t)})}function E(n){const{children:o}=n,c=(0,t.default)(n,l);return(0,u.jsx)(h,Object.assign({},v(c),{children:o}))}E.ForEach=c.ListForEach},28,[3,4,5,29,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ListForEach=function(n){let{children:t,onDelete:l,onMove:u}=n,h=(0,o.default)(n,v);return(0,c.jsx)(s,Object.assign({},h,{onDelete:l?({nativeEvent:n})=>l(n.indices):void 0,onMove:u?({nativeEvent:n})=>u(n.sourceIndices,n.destination):void 0,children:t}))};var o=n(r(d[1])),t=r(d[2]),c=r(d[3]);const v=["children","onDelete","onMove"],s=(0,t.requireNativeView)('ExpoUI','ListForEachView')},29,[3,4,5,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Menu=function(n){const{label:o,children:y,systemImage:b,onPrimaryAction:v}=n,f=(0,t.default)(n,s),h='string'==typeof o;return(0,l.jsxs)(c,Object.assign({label:h?o:void 0,systemImage:b,hasPrimaryAction:null!=v,onPrimaryAction:v},f,{children:[!h&&(0,l.jsx)(u,{children:o}),y]}))};var t=n(r(d[1])),o=r(d[2]),l=r(d[3]);const s=["label","children","systemImage","onPrimaryAction"],c=(0,o.requireNativeView)('ExpoUI','MenuView'),u=(0,o.requireNativeView)('ExpoUI','MenuLabel')},30,[3,4,5,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Picker=function(n){const c=j(n),{label:o,children:s}=c,b=(0,t.default)(c,u);return'string'==typeof o?(0,l.jsx)(f,Object.assign({},b,{label:o,children:(0,l.jsx)(v,{children:s})})):(0,l.jsxs)(f,Object.assign({},b,{children:[(0,l.jsx)(h,{children:o}),(0,l.jsx)(v,{children:s})]}))};var t=n(r(d[1])),c=r(d[2]),o=r(d[3]),l=r(d[4]);const s=["modifiers","onSelectionChange"],u=["label","children"],f=(0,c.requireNativeView)('ExpoUI','PickerView'),v=(0,c.requireNativeView)('ExpoUI','PickerContentView'),h=(0,c.requireNativeView)('ExpoUI','PickerLabelView');function j(n){const{modifiers:c,onSelectionChange:l}=n,u=(0,t.default)(n,s);return Object.assign({modifiers:c},c?(0,o.createViewModifierEventListener)(c):void 0,u,{onSelectionChange:l?({nativeEvent:{selection:n}})=>{l(n)}:void 0})}},31,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ProgressView=function(t){const{modifiers:n,timerInterval:l}=t,c=(0,o.default)(t,u);return(0,v.jsx)(f,Object.assign({modifiers:n},n?(0,s.createViewModifierEventListener)(n):void 0,c,{timerInterval:l?{lower:l.lower.getTime(),upper:l.upper.getTime()}:void 0}))};var o=t(r(d[1])),n=r(d[2]),s=r(d[3]),v=r(d[4]);const u=["modifiers","timerInterval"],f=(0,n.requireNativeView)('ExpoUI','ProgressView')},32,[3,4,5,6,7]); -__d(function(g,r,i,a,m,_e,d){var e=r(d[0]);Object.defineProperty(_e,"__esModule",{value:!0}),_e.Section=function(e){const{modifiers:o,header:u,footer:E,children:l,onIsExpandedChange:p}=e,I=(0,n.default)(e,s);return(0,c.jsxs)(x,Object.assign({modifiers:o},o?(0,t.createViewModifierEventListener)(o):void 0,p&&{onIsExpandedChange:e=>p(e.nativeEvent.isExpanded)},I,{children:[u&&(0,c.jsx)(h,{children:u}),E&&(0,c.jsx)(v,{children:E}),(0,c.jsx)(f,{children:l})]}))};var n=e(r(d[1])),o=r(d[2]),t=r(d[3]),c=r(d[4]);const s=["modifiers","header","footer","children","onIsExpandedChange"],x=(0,o.requireNativeView)('ExpoUI','SectionView'),h=(0,o.requireNativeView)('ExpoUI','SectionHeader'),v=(0,o.requireNativeView)('ExpoUI','SectionFooter'),f=(0,o.requireNativeView)('ExpoUI','SectionContent')},33,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ShareLink=function(t){const{modifiers:s,getItemAsync:v,item:y}=t,I=(0,n.default)(t,f),w=(0,c.useRef)(null),h=(0,c.useCallback)(async()=>{if(v&&w.current&&!y)try{const t=await v();w.current.setItem(t)}catch(t){throw w.current.setItem(null),t}},[v,y]);return(0,u.jsx)(l,Object.assign({modifiers:s},s?(0,o.createViewModifierEventListener)(s):void 0,I,{ref:w,item:y,onAsyncItemRequest:h}))};var n=t(r(d[1])),s=r(d[2]),c=r(d[3]),o=r(d[4]),u=r(d[5]);const f=["modifiers","getItemAsync","item"],l=(0,s.requireNativeView)('ExpoUI','ShareLinkView')},34,[3,4,5,11,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Slider=function(n){const{label:l,minimumValueLabel:u,maximumValueLabel:o}=n;return(0,t.jsxs)(s,Object.assign({},v(n),{children:[l&&(0,t.jsx)(c,{kind:"label",children:l}),u&&(0,t.jsx)(c,{kind:"minimum",children:u}),o&&(0,t.jsx)(c,{kind:"maximum",children:o})]}))};var l=n(r(d[1])),u=r(d[2]),t=r(d[3]);const o=["label","minimumValueLabel","maximumValueLabel","onValueChange","onEditingChanged"],s=(0,u.requireNativeView)('ExpoUI','SliderView'),c=(0,u.requireNativeView)('ExpoUI','SliderLabelView');function v(n){const{onValueChange:u,onEditingChanged:t}=n,s=(0,l.default)(n,o);return Object.assign({},s,{onValueChanged:u?({nativeEvent:{value:n}})=>{u(n)}:void 0,onEditingChanged:t?({nativeEvent:{isEditing:n}})=>{t(n)}:void 0})}},35,[3,4,5,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Spacer=function(t){return(0,c.jsx)(u,Object.assign({},v(t)))};var n=t(r(d[1])),o=r(d[2]),s=r(d[3]),c=r(d[4]);const f=["modifiers"],u=(0,o.requireNativeView)('ExpoUI','SpacerView');function v(t){const{modifiers:o}=t,c=(0,n.default)(t,f);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,c)}},36,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Stepper=function(n){return(0,u.jsx)(f,Object.assign({},v(n)))};var t=n(r(d[1])),o=r(d[2]),s=r(d[3]),u=r(d[4]);const c=["modifiers"],f=(0,o.requireNativeView)('ExpoUI','StepperView');function v(n){const{modifiers:o}=n,u=(0,t.default)(n,c);return Object.assign({modifiers:o},o?(0,s.createViewModifierEventListener)(o):void 0,u,{onValueChanged:({nativeEvent:{value:t}})=>{n.onValueChanged(t)}})}},37,[3,4,5,6,7]); -__d(function(g,_r,_i,_a,m,_e,d){var e=_r(d[0]);Object.defineProperty(_e,"__esModule",{value:!0}),_e.Text=function e(r){const{children:u,modifiers:c}=r,a=(0,t.default)(r,f);if(!u)return null;const l=n.Children.toArray(u);if(0===l.length)return null;if(l.every(e=>'string'==typeof e||'number'==typeof e)){const e=l.map(String).join('');return(0,o.jsx)(s,Object.assign({text:e,modifiers:c},c?(0,i.createViewModifierEventListener)(c):void 0,a))}const p=[];let y=0;for(const t of l)'string'==typeof t||'number'==typeof t?p.push((0,o.jsx)(s,{text:String(t)},"text-"+y++)):n.isValidElement(t)&&t.type===e&&p.push(t);return(0,o.jsx)(s,Object.assign({modifiers:c},c?(0,i.createViewModifierEventListener)(c):void 0,a,{children:p}))};var t=e(_r(d[1])),r=_r(d[2]),n=(function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var r=u(t);if(r&&r.has(e))return r.get(e);var n={__proto__:null},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if("default"!==o&&{}.hasOwnProperty.call(e,o)){var f=i?Object.getOwnPropertyDescriptor(e,o):null;f&&(f.get||f.set)?Object.defineProperty(n,o,f):n[o]=e[o]}return n.default=e,r&&r.set(e,n),n})(_r(d[3])),i=_r(d[4]),o=_r(d[5]);const f=["children","modifiers"];function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(u=function(e){return e?r:t})(e)}const s=(0,r.requireNativeView)('ExpoUI','TextView')},38,[3,4,5,11,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Toggle=function(n){const{children:s,onIsOnChange:v,modifiers:u}=n,O=(0,o.default)(n,f),h=Object.assign({},O,{modifiers:u},u?(0,t.createViewModifierEventListener)(u):void 0,{onIsOnChange:({nativeEvent:{isOn:n}})=>{v?.(n)}});return(0,c.jsx)(l,Object.assign({},h,{children:s}))};var o=n(r(d[1])),s=r(d[2]),t=r(d[3]),c=r(d[4]);const f=["children","onIsOnChange","modifiers"],l=(0,s.requireNativeView)('ExpoUI','ToggleView')},39,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.TextField=function(n){return(0,u.jsx)(c,Object.assign({},l(n)))};var t=n(r(d[1])),o=r(d[2]),v=r(d[3]),u=r(d[4]);const s=["modifiers"],c=(0,o.requireNativeView)('ExpoUI','TextFieldView');function l(n){const{modifiers:o}=n,u=(0,t.default)(n,s);return Object.assign({modifiers:o},o?(0,v.createViewModifierEventListener)(o):void 0,u,{onValueChanged:t=>{n.onChangeText?.(t.nativeEvent.value)},onFocusChanged:t=>{n.onChangeFocus?.(t.nativeEvent.value)},onSelectionChanged:t=>{n.onChangeSelection?.({start:t.nativeEvent.start,end:t.nativeEvent.end})},onSubmit:t=>{n.onSubmit?.(t.nativeEvent.value)}})}},40,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.SecureField=function(n){return(0,v.jsx)(c,Object.assign({},f(n)))};var t=n(r(d[1])),o=r(d[2]),u=r(d[3]),v=r(d[4]);const s=["modifiers"],c=(0,o.requireNativeView)('ExpoUI','SecureFieldView');function f(n){const{modifiers:o}=n,v=(0,t.default)(n,s);return Object.assign({modifiers:o},o?(0,u.createViewModifierEventListener)(o):void 0,v,{onValueChanged:t=>{n.onChangeText?.(t.nativeEvent.value)},onFocusChanged:t=>{n.onChangeFocus?.(t.nativeEvent.value)},onSubmit:t=>{n.onSubmit?.(t.nativeEvent.value)}})}},41,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.Namespace=function(n){return(0,t.jsx)(c,Object.assign({},n))};var n=r(d[0]),t=r(d[1]);const c=(0,n.requireNativeView)('ExpoUI','NamespaceView')},42,[5,7]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.GlassEffectContainer=function(t){const f=t.modifiers?(0,n.createViewModifierEventListener)(t.modifiers):void 0;return(0,o.jsx)(s,Object.assign({},t,f))};var t=r(d[0]),n=r(d[1]),o=r(d[2]);const s=(0,t.requireNativeView)('ExpoUI','GlassEffectContainerView')},43,[5,6,7]); -__d(function(g,r,i,a,m,e,d){var t=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0});var n={Rectangle:!0,RoundedRectangle:!0,Ellipse:!0,UnevenRoundedRectangle:!0,Capsule:!0,Circle:!0};e.Capsule=function(t){const{modifiers:n}=t,s=(0,o.default)(t,p);return(0,f.jsx)(O,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))},e.Circle=function(t){const{modifiers:n}=t,s=(0,o.default)(t,j);return(0,f.jsx)(U,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))},e.Ellipse=function(t){const{modifiers:n}=t,s=(0,o.default)(t,w);return(0,f.jsx)(x,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))},e.Rectangle=function(t){const{modifiers:n}=t,s=(0,o.default)(t,l);return(0,f.jsx)(E,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))},e.RoundedRectangle=function(t){const{modifiers:n}=t,s=(0,o.default)(t,v);return(0,f.jsx)(R,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))},e.UnevenRoundedRectangle=function(t){const{modifiers:n}=t,s=(0,o.default)(t,V);return(0,f.jsx)(b,Object.assign({},s,{modifiers:n},n?(0,c.createViewModifierEventListener)(n):void 0))};var o=t(r(d[1])),s=r(d[2]),c=r(d[3]),f=r(d[4]),u=r(d[5]);Object.keys(u).forEach(function(t){"default"!==t&&"__esModule"!==t&&(Object.prototype.hasOwnProperty.call(n,t)||t in e&&e[t]===u[t]||Object.defineProperty(e,t,{enumerable:!0,get:function(){return u[t]}}))});const l=["modifiers"],v=["modifiers"],w=["modifiers"],V=["modifiers"],p=["modifiers"],j=["modifiers"],E=(0,s.requireNativeView)('ExpoUI','RectangleView');const R=(0,s.requireNativeView)('ExpoUI','RoundedRectangleView');const x=(0,s.requireNativeView)('ExpoUI','EllipseView');const b=(0,s.requireNativeView)('ExpoUI','UnevenRoundedRectangleView');const O=(0,s.requireNativeView)('ExpoUI','CapsuleView');const U=(0,s.requireNativeView)('ExpoUI','CircleView')},44,[3,4,5,6,7,45]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.ConcentricRectangle=function(n){const{modifiers:c}=n,l=(0,t.default)(n,f);return(0,s.jsx)(u,Object.assign({},l,{modifiers:c},c?(0,o.createViewModifierEventListener)(c):void 0))},e.EdgeCornerStyle=void 0;var t=n(r(d[1])),c=r(d[2]),o=r(d[3]),s=r(d[4]);const f=["modifiers"],u=(e.EdgeCornerStyle={concentric:n=>({type:'concentric',minimumRadius:n}),fixed:n=>({type:'fixed',radius:n})},(0,c.requireNativeView)('ExpoUI','ConcentricRectangleView'))},45,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Popover=p;var t=n(r(d[1])),o=r(d[2]),s=r(d[3]),c=r(d[4]);const v=["onIsPresentedChange","modifiers","children","isPresented"],u=(0,o.requireNativeView)('ExpoUI','PopoverView'),P=(0,o.requireNativeView)('ExpoUI','PopoverViewContent'),f=(0,o.requireNativeView)('ExpoUI','PopoverViewPopContent');function p(n){const{onIsPresentedChange:o,modifiers:P,children:f,isPresented:p}=n,j=(0,t.default)(n,v);return(0,c.jsx)(u,Object.assign({},P?(0,s.createViewModifierEventListener)(P):void 0,j,{isPresented:p,onIsPresentedChange:n=>{o?.(n.nativeEvent.isPresented)},children:f}))}p.Trigger=function(n){return(0,c.jsx)(P,Object.assign({},n))},p.Content=function(n){return(0,c.jsx)(f,Object.assign({},n))}},46,[3,4,5,6,7]); -__d(function(g,r,i,a,m,e,d){var n=r(d[0]);Object.defineProperty(e,"__esModule",{value:!0}),e.Grid=v;var o=n(r(d[1])),t=r(d[2]),c=(n(r(d[3])),r(d[4])),s=r(d[5]);const f=["modifiers","children"],l=(0,t.requireNativeView)('ExpoUI','GridView'),u=(0,t.requireNativeView)('ExpoUI','GridRowView');function v(n){const{modifiers:t,children:u}=n,v=(0,o.default)(n,f);return(0,s.jsx)(l,Object.assign({modifiers:t},t?(0,c.createViewModifierEventListener)(t):void 0,v,{children:u}))}v.Row=({children:n})=>(0,s.jsx)(u,{children:n})},47,[3,4,5,11,6,7]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.RNHostView=function(t){return(0,n.createElement)(o,Object.assign({},t,{key:t.matchContents?'matchContents':'noMatchContents'}))};var t=r(d[0]),n=r(d[1]);const o=(0,t.requireNativeView)('ExpoUI','RNHostView')},48,[5,11]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0});var t={listSectionSpacing:!0,cornerRadius:!0,shadow:!0,matchedGeometryEffect:!0,frame:!0,containerRelativeFrame:!0,padding:!0,fixedSize:!0,ignoreSafeArea:!0,onTapGesture:!0,onLongPressGesture:!0,onAppear:!0,onDisappear:!0,refreshable:!0,opacity:!0,clipShape:!0,border:!0,scaleEffect:!0,rotationEffect:!0,offset:!0,foregroundColor:!0,foregroundStyle:!0,bold:!0,italic:!0,tint:!0,hidden:!0,disabled:!0,zIndex:!0,blur:!0,brightness:!0,contrast:!0,saturation:!0,hueRotation:!0,colorInvert:!0,grayscale:!0,buttonStyle:!0,toggleStyle:!0,controlSize:!0,labelStyle:!0,labelsHidden:!0,textFieldStyle:!0,scrollDismissesKeyboard:!0,scrollDisabled:!0,moveDisabled:!0,deleteDisabled:!0,menuActionDismissBehavior:!0,accessibilityLabel:!0,accessibilityHint:!0,accessibilityValue:!0,layoutPriority:!0,mask:!0,overlay:!0,backgroundOverlay:!0,aspectRatio:!0,clipped:!0,glassEffect:!0,glassEffectId:!0,scrollContentBackground:!0,listRowBackground:!0,listRowSeparator:!0,truncationMode:!0,allowsTightening:!0,kerning:!0,textCase:!0,underline:!0,strikethrough:!0,multilineTextAlignment:!0,textSelection:!0,lineSpacing:!0,lineLimit:!0,headerProminence:!0,listRowInsets:!0,badgeProminence:!0,badge:!0,listSectionMargins:!0,font:!0,gridCellUnsizedAxes:!0,gridCellColumns:!0,gridColumnAlignment:!0,gridCellAnchor:!0,submitLabel:!0,listStyle:!0,isModifier:!0,filterModifiers:!0};e.zIndex=e.underline=e.truncationMode=e.toggleStyle=e.tint=e.textSelection=e.textFieldStyle=e.textCase=e.submitLabel=e.strikethrough=e.shadow=e.scrollDismissesKeyboard=e.scrollDisabled=e.scrollContentBackground=e.scaleEffect=e.saturation=e.rotationEffect=e.refreshable=e.padding=e.overlay=e.opacity=e.onTapGesture=e.onLongPressGesture=e.onDisappear=e.onAppear=e.offset=e.multilineTextAlignment=e.moveDisabled=e.menuActionDismissBehavior=e.matchedGeometryEffect=e.mask=e.listStyle=e.listSectionSpacing=e.listSectionMargins=e.listRowSeparator=e.listRowInsets=e.listRowBackground=e.lineSpacing=e.lineLimit=e.layoutPriority=e.labelsHidden=e.labelStyle=e.kerning=e.italic=e.isModifier=e.ignoreSafeArea=e.hueRotation=e.hidden=e.headerProminence=e.gridColumnAlignment=e.gridCellUnsizedAxes=e.gridCellColumns=e.gridCellAnchor=e.grayscale=e.glassEffectId=e.glassEffect=e.frame=e.foregroundStyle=e.foregroundColor=e.font=e.fixedSize=e.filterModifiers=e.disabled=e.deleteDisabled=e.cornerRadius=e.controlSize=e.contrast=e.containerRelativeFrame=e.colorInvert=e.clipped=e.clipShape=e.buttonStyle=e.brightness=e.border=e.bold=e.blur=e.badgeProminence=e.badge=e.backgroundOverlay=e.aspectRatio=e.allowsTightening=e.accessibilityValue=e.accessibilityLabel=e.accessibilityHint=void 0;var o=r(d[0]),n=r(d[1]);Object.keys(n).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===n[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return n[o]}}))});var l=r(d[2]);Object.keys(l).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===l[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return l[o]}}))});var c=r(d[3]);Object.keys(c).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===c[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return c[o]}}))});var s=r(d[4]);Object.keys(s).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===s[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return s[o]}}))});var f=r(d[5]);Object.keys(f).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===f[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return f[o]}}))});var u=r(d[6]);Object.keys(u).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===u[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return u[o]}}))});var b=r(d[7]);Object.keys(b).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===b[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return b[o]}}))});var y=r(d[8]);Object.keys(y).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===y[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return y[o]}}))});var p=r(d[9]);Object.keys(p).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===p[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return p[o]}}))});var M=r(d[10]);Object.keys(M).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===M[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return M[o]}}))});var h=r(d[11]);Object.keys(h).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===h[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return h[o]}}))});var S=r(d[12]);Object.keys(S).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===S[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return S[o]}}))});var O=r(d[13]);Object.keys(O).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===O[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return O[o]}}))});var v=r(d[14]);Object.keys(v).forEach(function(o){"default"!==o&&"__esModule"!==o&&(Object.prototype.hasOwnProperty.call(t,o)||o in e&&e[o]===v[o]||Object.defineProperty(e,o,{enumerable:!0,get:function(){return v[o]}}))});const j=(0,o.requireNativeModule)('ExpoUI');function P(t,o,n={}){return Object.assign({$type:t},n,{eventListener:o})}e.listSectionSpacing=t=>'number'==typeof t?(0,n.createModifier)('listSectionSpacing',{spacing:'custom',value:t}):(0,n.createModifier)('listSectionSpacing',{spacing:t});e.cornerRadius=t=>(0,n.createModifier)('cornerRadius',{radius:t});e.shadow=t=>(0,n.createModifier)('shadow',t);e.matchedGeometryEffect=(t,o)=>(0,n.createModifier)('matchedGeometryEffect',{id:t,namespaceId:o});e.frame=t=>(0,n.createModifier)('frame',t);e.containerRelativeFrame=t=>(0,n.createModifier)('containerRelativeFrame',t);e.padding=t=>(0,n.createModifier)('padding',t);e.fixedSize=t=>(0,n.createModifier)('fixedSize',t);e.ignoreSafeArea=t=>(0,n.createModifier)('ignoreSafeArea',t);e.onTapGesture=t=>P('onTapGesture',t);e.onLongPressGesture=(t,o)=>P('onLongPressGesture',t,{minimumDuration:o??.5});e.onAppear=t=>P('onAppear',t);e.onDisappear=t=>P('onDisappear',t);e.refreshable=t=>P('refreshable',async o=>{try{await t()}finally{await j.completeRefresh(o.id)}});e.opacity=t=>(0,n.createModifier)('opacity',{value:t});e.clipShape=(t,o)=>(0,n.createModifier)('clipShape',{shape:t,cornerRadius:o});e.border=t=>(0,n.createModifier)('border',t);e.scaleEffect=t=>(0,n.createModifier)('scaleEffect',{scale:t});e.rotationEffect=t=>(0,n.createModifier)('rotationEffect',{angle:t});e.offset=t=>(0,n.createModifier)('offset',t);e.foregroundColor=t=>(0,n.createModifier)('foregroundColor',{color:t});e.foregroundStyle=t=>'string'==typeof t?(0,n.createModifier)('foregroundStyle',{styleType:'color',color:t}):(0,n.createModifier)('foregroundStyle',Object.assign({styleType:t.type},t));e.bold=()=>(0,n.createModifier)('bold',{});e.italic=()=>(0,n.createModifier)('italic',{});e.tint=t=>(0,n.createModifier)('tint',{color:t});e.hidden=(t=!0)=>(0,n.createModifier)('hidden',{hidden:t});e.disabled=(t=!0)=>(0,n.createModifier)('disabled',{disabled:t});e.zIndex=t=>(0,n.createModifier)('zIndex',{index:t});e.blur=t=>(0,n.createModifier)('blur',{radius:t});e.brightness=t=>(0,n.createModifier)('brightness',{amount:t});e.contrast=t=>(0,n.createModifier)('contrast',{amount:t});e.saturation=t=>(0,n.createModifier)('saturation',{amount:t});e.hueRotation=t=>(0,n.createModifier)('hueRotation',{angle:t});e.colorInvert=(t=!0)=>(0,n.createModifier)('colorInvert',{inverted:t});e.grayscale=t=>(0,n.createModifier)('grayscale',{amount:t});e.buttonStyle=t=>(0,n.createModifier)('buttonStyle',{style:t});e.toggleStyle=t=>(0,n.createModifier)('toggleStyle',{style:t});e.controlSize=t=>(0,n.createModifier)('controlSize',{size:t});e.labelStyle=t=>(0,n.createModifier)('labelStyle',{style:t});e.labelsHidden=()=>(0,n.createModifier)('labelsHidden',{});e.textFieldStyle=t=>(0,n.createModifier)('textFieldStyle',{style:t});e.scrollDismissesKeyboard=t=>(0,n.createModifier)('scrollDismissesKeyboard',{mode:t});e.scrollDisabled=(t=!0)=>(0,n.createModifier)('scrollDisabled',{disabled:t});e.moveDisabled=(t=!0)=>(0,n.createModifier)('moveDisabled',{disabled:t});e.deleteDisabled=(t=!0)=>(0,n.createModifier)('deleteDisabled',{disabled:t});e.menuActionDismissBehavior=t=>(0,n.createModifier)('menuActionDismissBehavior',{behavior:t});e.accessibilityLabel=t=>(0,n.createModifier)('accessibilityLabel',{label:t});e.accessibilityHint=t=>(0,n.createModifier)('accessibilityHint',{hint:t});e.accessibilityValue=t=>(0,n.createModifier)('accessibilityValue',{value:t});e.layoutPriority=t=>(0,n.createModifier)('layoutPriority',{priority:t});e.mask=(t,o)=>(0,n.createModifier)('mask',{shape:t,cornerRadius:o});e.overlay=t=>(0,n.createModifier)('overlay',t);e.backgroundOverlay=t=>(0,n.createModifier)('backgroundOverlay',t);e.aspectRatio=t=>(0,n.createModifier)('aspectRatio',t);e.clipped=(t=!0)=>(0,n.createModifier)('clipped',{clipped:t});e.glassEffect=t=>(0,n.createModifier)('glassEffect',t);e.glassEffectId=(t,o)=>(0,n.createModifier)('glassEffectId',{id:t,namespaceId:o});e.scrollContentBackground=t=>(0,n.createModifier)('scrollContentBackground',{visible:t});e.listRowBackground=t=>(0,n.createModifier)('listRowBackground',{color:t});e.listRowSeparator=(t,o)=>(0,n.createModifier)('listRowSeparator',{visibility:t,edges:o});e.truncationMode=t=>(0,n.createModifier)('truncationMode',{mode:t});e.allowsTightening=t=>(0,n.createModifier)('allowsTightening',{value:t});e.kerning=t=>(0,n.createModifier)('kerning',{value:t});e.textCase=t=>(0,n.createModifier)('textCase',{value:t});e.underline=t=>(0,n.createModifier)('underline',t);e.strikethrough=t=>(0,n.createModifier)('strikethrough',t);e.multilineTextAlignment=t=>(0,n.createModifier)('multilineTextAlignment',{alignment:t});e.textSelection=t=>(0,n.createModifier)('textSelection',{value:t});e.lineSpacing=t=>(0,n.createModifier)('lineSpacing',{value:t});e.lineLimit=t=>(0,n.createModifier)('lineLimit',{limit:t});e.headerProminence=t=>(0,n.createModifier)('headerProminence',{prominence:t});e.listRowInsets=t=>(0,n.createModifier)('listRowInsets',t);e.badgeProminence=t=>(0,n.createModifier)('badgeProminence',{badgeType:t});e.badge=t=>(0,n.createModifier)('badge',{value:t});e.listSectionMargins=t=>(0,n.createModifier)('listSectionMargins',t);e.font=t=>(0,n.createModifier)('font',t);e.gridCellUnsizedAxes=t=>(0,n.createModifier)('gridCellUnsizedAxes',{axes:t});e.gridCellColumns=t=>(0,n.createModifier)('gridCellColumns',{count:t});e.gridColumnAlignment=t=>(0,n.createModifier)('gridColumnAlignment',{alignment:t});e.gridCellAnchor=t=>(0,n.createModifier)('gridCellAnchor',t);e.submitLabel=t=>(0,n.createModifier)('submitLabel',{submitLabel:t});e.listStyle=t=>(0,n.createModifier)('listStyle',{style:t});const k=t=>'object'==typeof t&&null!==t&&'string'==typeof t.$type;e.isModifier=k;e.filterModifiers=t=>t.filter(k)},49,[5,50,6,51,53,54,55,56,57,58,59,60,61,62,63]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.createModifier=function(t,n={}){return Object.assign({$type:t},n)}},50,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.animation=e.Animation=void 0;var n=r(d[0]),t=r(d[1]);e.Animation={easeInOut:n=>o({type:'easeInOut',duration:n?.duration}),easeIn:n=>o({type:'easeIn',duration:n?.duration}),easeOut:n=>o({type:'easeOut',duration:n?.duration}),linear:n=>o({type:'linear',duration:n?.duration}),spring:n=>o({type:'spring',response:n?.response,dampingFraction:n?.dampingFraction,blendDuration:n?.blendDuration,duration:n?.duration,bounce:n?.bounce}),interpolatingSpring:n=>o({type:'interpolatingSpring',mass:n?.mass,stiffness:n?.stiffness,damping:n?.damping,initialVelocity:n?.initialVelocity,duration:n?.duration,bounce:n?.bounce}),default:o({type:'default'})};function o(n){let u=n;return{delay:n=>(u=Object.assign({},u,{delay:n}),o(u)),repeat:n=>(u=Object.assign({},u,n),o(u)),[t.VALUE_SYMBOL]:()=>u}}e.animation=(o,u)=>(0,n.createModifier)('animation',{animation:o[t.VALUE_SYMBOL](),animatedValue:u})},51,[50,52]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.VALUE_SYMBOL=void 0;e.VALUE_SYMBOL=Symbol('value')},52,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.containerShape=void 0;var n=r(d[0]);e.containerShape=o=>(0,n.createModifier)('containerShape',o)},53,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.contentShape=void 0;var t=r(d[0]);e.contentShape=n=>(0,t.createModifier)('contentShape',n)},54,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.shapes=void 0;e.shapes={roundedRectangle:n=>({cornerRadius:n.cornerRadius,roundedCornerStyle:n.roundedCornerStyle,cornerSize:n.cornerSize,shape:'roundedRectangle'}),capsule:n=>({roundedCornerStyle:n?.roundedCornerStyle,shape:'capsule'}),rectangle:()=>({shape:'rectangle'}),ellipse:()=>({shape:'ellipse'}),circle:()=>({shape:'circle'})}},55,[]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.background=void 0;var o=r(d[0]);e.background=(c,n)=>(0,o.createModifier)('background',Object.assign({color:c},n))},56,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.tag=void 0;var t=r(d[0]);e.tag=o=>(0,t.createModifier)('tag',{tag:o})},57,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.pickerStyle=void 0;var t=r(d[0]);e.pickerStyle=c=>(0,t.createModifier)('pickerStyle',{style:c})},58,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.datePickerStyle=void 0;var t=r(d[0]);e.datePickerStyle=c=>(0,t.createModifier)('datePickerStyle',{style:c})},59,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.progressViewStyle=void 0;var o=r(d[0]);e.progressViewStyle=s=>(0,o.createModifier)('progressViewStyle',{style:s})},60,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.gaugeStyle=void 0;var t=r(d[0]);e.gaugeStyle=l=>(0,t.createModifier)('gaugeStyle',{style:l})},61,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.presentationDragIndicator=e.presentationDetents=e.presentationBackgroundInteraction=e.interactiveDismissDisabled=void 0;var t=r(d[0]);e.presentationDetents=n=>(0,t.createModifier)('presentationDetents',{detents:n});e.presentationDragIndicator=n=>(0,t.createModifier)('presentationDragIndicator',{visibility:n});e.presentationBackgroundInteraction=n=>'string'==typeof n?(0,t.createModifier)('presentationBackgroundInteraction',{interactionType:n}):(0,t.createModifier)('presentationBackgroundInteraction',{interactionType:'enabledUpThrough',detent:n.detent});e.interactiveDismissDisabled=(n=!0)=>(0,t.createModifier)('interactiveDismissDisabled',{isDisabled:n})},62,[50]); -__d(function(g,r,i,a,m,e,d){Object.defineProperty(e,"__esModule",{value:!0}),e.environment=void 0;var n=r(d[0]);e.environment=(o,t)=>(0,n.createModifier)('environment',{key:o,value:t})},63,[50]); -__r(0); -""" diff --git a/packages/expo-widgets/metro.config.js b/packages/expo-widgets/metro.config.js new file mode 100644 index 00000000000000..b0637ae8db2e8f --- /dev/null +++ b/packages/expo-widgets/metro.config.js @@ -0,0 +1,56 @@ +const { getDefaultConfig } = require('expo/metro-config'); +const resolve = require('metro-resolver').resolve; +const path = require('path'); + +const config = getDefaultConfig(__dirname); +const emptyModulePath = require.resolve('metro-runtime/src/modules/empty-module'); +const expoStubPath = path.resolve(__dirname, './bundle/expo-module-stub.ts'); +const reactStubPath = path.resolve(__dirname, './bundle/react-stub.ts'); +const jsxRuntimeStubPath = path.resolve(__dirname, './bundle/jsx-runtime-stub.ts'); + +const buildConfig = { + ...config, + resolver: { + ...config.resolver, + resolveRequest(context, moduleName) { + const resolvedPlatform = 'ios'; + if (moduleName === 'expo') { + return { type: 'sourceFile', filePath: expoStubPath }; + } + if (moduleName === 'react') { + return { type: 'sourceFile', filePath: reactStubPath }; + } + if (moduleName === 'react/jsx-runtime') { + return { type: 'sourceFile', filePath: jsxRuntimeStubPath }; + } + if (moduleName === 'react/jsx-dev-runtime') { + return { type: 'sourceFile', filePath: jsxRuntimeStubPath }; + } + + if ( + moduleName.startsWith('@expo/ui') || + moduleName.startsWith('@babel/runtime') || + moduleName.startsWith('./') || + moduleName.startsWith('../') || + path.isAbsolute(moduleName) + ) { + return resolve(context, moduleName, resolvedPlatform); + } + + return { type: 'sourceFile', filePath: emptyModulePath }; + }, + }, + transformer: { + ...config.transformer, + babelTransformerPath: require.resolve('@expo/metro-config/build/babel-transformer'), + getTransformOptions: async () => ({ + transform: { experimentalImportSupport: false, inlineRequires: false }, + }), + }, + serializer: { + ...config.serializer, + getPolyfills: () => [], + }, +}; + +module.exports = buildConfig; diff --git a/packages/expo-widgets/package.json b/packages/expo-widgets/package.json index 3a0af4fadcc5ab..df8bb222a1be4d 100644 --- a/packages/expo-widgets/package.json +++ b/packages/expo-widgets/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "expo-module build", "build:plugin": "expo-module build plugin", + "build:bundle": "node ./scripts/build-bundle.mjs", "clean": "expo-module clean", "lint": "expo-module lint", "test": "expo-module test", diff --git a/packages/expo-widgets/scripts/build-bundle.mjs b/packages/expo-widgets/scripts/build-bundle.mjs new file mode 100755 index 00000000000000..e53db98644f62d --- /dev/null +++ b/packages/expo-widgets/scripts/build-bundle.mjs @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +// Build the ExpoWidgets.bundle. +// Use `yarn build:bundle` to run this script. + +import spawn from '@expo/spawn-async'; +import { rm } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { dirname, join } from 'path'; +import { argv } from 'process'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +// NODE_BINARY is set for Xcode builds via the `with-node.sh` script. +const nodePath = process.env.NODE_BINARY || 'node'; +const outputDir = join(__dirname, '../bundle/build'); +const appBundlePath = join(outputDir, 'ExpoWidgets.bundle'); + +await rm(outputDir, { recursive: true, force: true }); + +const expoCliJs = createRequire(__dirname).resolve('expo/bin/cli'); + +const result = await spawn( + nodePath, + [ + expoCliJs, + 'export:embed', + '--platform', + 'ios', + '--bundle-output', + appBundlePath, + '--entry-file', + join(__dirname, '../bundle/index.ts'), + '--dev', + false, + ...argv.slice(2), + ], + { + stdio: 'inherit', + cwd: join(__dirname, '..'), + } +); + +if (result.error) { + process.exit(1); +} diff --git a/packages/expo-widgets/scripts/with-node.sh b/packages/expo-widgets/scripts/with-node.sh new file mode 100755 index 00000000000000..41b6b3b715d6b0 --- /dev/null +++ b/packages/expo-widgets/scripts/with-node.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# Copyright 2018-present 650 Industries. All rights reserved. +# +# @generated by expo-module-scripts +# +# USAGE: +# ./with-node.sh command + +CURR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" + +# Start with a default +NODE_BINARY=$(command -v node) +export NODE_BINARY + +# Override the default with the global environment +ENV_PATH="$PODS_ROOT/../.xcode.env" +if [[ -f "$ENV_PATH" ]]; then + source "$ENV_PATH" +fi + +# Override the global with the local environment +LOCAL_ENV_PATH="${ENV_PATH}.local" +if [[ -f "$LOCAL_ENV_PATH" ]]; then + source "$LOCAL_ENV_PATH" +fi + +if [[ -n "$NODE_BINARY" && -x "$NODE_BINARY" ]]; then + echo "Node found at: ${NODE_BINARY}" +else + cat >&2 << EOF +[ERROR] Could not find "node" while running an Xcode build script. You need to specify the path to your Node.js executable by defining an environment variable named NODE_BINARY in your project's .xcode.env or .xcode.env.local file. You can set this up quickly by running: + + echo "export NODE_BINARY=\$(command -v node)" >> .xcode.env + +in the ios folder of your project. +EOF + exit 1 +fi + +# Execute argument, if present +if [[ "$#" -gt 0 ]]; then + "$NODE_BINARY" "$@" +fi diff --git a/packages/expo/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt b/packages/expo/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt index d5918273c9458b..74f9d8a5acd466 100644 --- a/packages/expo/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt +++ b/packages/expo/android/src/main/java/expo/modules/ReactActivityDelegateWrapper.kt @@ -19,15 +19,12 @@ import com.facebook.react.ReactActivity import com.facebook.react.ReactActivityDelegate import com.facebook.react.ReactDelegate import com.facebook.react.ReactHost -import com.facebook.react.ReactInstanceEventListener import com.facebook.react.ReactInstanceManager import com.facebook.react.ReactRootView -import com.facebook.react.bridge.ReactContext import com.facebook.react.modules.core.PermissionListener import expo.modules.core.interfaces.ReactActivityHandler.DelayLoadAppHandler import expo.modules.core.interfaces.ReactActivityLifecycleListener import expo.modules.kotlin.Utils -import expo.modules.rncompatibility.ReactNativeFeatureFlags import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineStart @@ -43,7 +40,7 @@ import kotlin.coroutines.suspendCoroutine class ReactActivityDelegateWrapper( private val activity: ReactActivity, - private val isNewArchitectureEnabled: Boolean, + private val isNewArchitectureEnabled: Boolean, // TODO(@lukmccall): Unused since SDK 55, remove in SDK 56 @get:VisibleForTesting internal var delegate: ReactActivityDelegate ) : ReactActivityDelegate(activity, null) { constructor(activity: ReactActivity, delegate: ReactActivityDelegate) : @@ -153,27 +150,12 @@ class ReactActivityDelegateWrapper( } val launchOptions = composeLaunchOptions() - val reactDelegate: ReactDelegate - if (ReactNativeFeatureFlags.enableBridgelessArchitecture) { - reactDelegate = ReactDelegate( - plainActivity, - reactHost, - mainComponentName, - launchOptions - ) - } else { - reactDelegate = object : ReactDelegate( - plainActivity, - reactNativeHost, - mainComponentName, - launchOptions, - isFabricEnabled - ) { - override fun createRootView(): ReactRootView? { - return this@ReactActivityDelegateWrapper.createRootView() ?: super.createRootView() - } - } - } + val reactDelegate = ReactDelegate( + plainActivity, + reactHost, + mainComponentName, + launchOptions + ) val mReactDelegate = ReactActivityDelegate::class.java.getDeclaredField("mReactDelegate") mReactDelegate.isAccessible = true @@ -273,18 +255,6 @@ class ReactActivityDelegateWrapper( */ launchLifecycleScopeWithLock { loadAppReady.await() - if (!ReactNativeFeatureFlags.enableBridgelessArchitecture && delegate.reactInstanceManager.currentReactContext == null) { - val reactContextListener = object : ReactInstanceEventListener { - override fun onReactContextInitialized(context: ReactContext) { - delegate.reactInstanceManager.removeReactInstanceEventListener(this) - delegate.onActivityResult(requestCode, resultCode, data) - } - } - return@launchLifecycleScopeWithLock delegate.reactInstanceManager.addReactInstanceEventListener( - reactContextListener - ) - } - delegate.onActivityResult(requestCode, resultCode, data) } }