From bcf40085db776e61cafb32609657973ebefda225 Mon Sep 17 00:00:00 2001 From: Aman Mittal Date: Mon, 16 Feb 2026 15:34:44 +0530 Subject: [PATCH 01/16] [docs] Revert extractFrontmatter to include full frontmatter in .md files (#43161) # Why Follow-up https://github.com/expo/expo/pull/43044 ## How - Reverted `extractFrontmatter()` in `scripts/generate-markdown-pages-utils.ts` to keep all frontmatter fields, only stripping lines with empty values (e.g. `modificationDate:` with no value from shallow CI clones). - Restored the original filter regex from `/^modificationDate:\s+\S/` (keep only modificationDate) back to `/^\w+:\s*$/` (strip empty-value lines). - Fixed the return delimiter format from `'---\n' + filtered + '\n---\n'` back to `'---\n' + filtered + '---\n'`. - Reverted the corresponding tests in `scripts/generate-markdown-pages-utils.test.ts` to match the pre-#43044 behavior. # Test Plan Run `yarn run export-preview` and then serve the `out` directory using `npx serve out`. Then, open a page in docs and click View Markdown: CleanShot 2026-02-16 at 12 42 31@2x Run `yarn test` and confirm the `extractFrontmatter` tests pass. # Checklist - [ ] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- .../generate-markdown-pages-utils.test.ts | 23 +++++++++++-------- docs/scripts/generate-markdown-pages-utils.ts | 7 +++--- 2 files changed, 17 insertions(+), 13 deletions(-) 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 { From 94a85a17153cd1d1938099f833a1a8aab54171e3 Mon Sep 17 00:00:00 2001 From: Vojtech Novak Date: Mon, 16 Feb 2026 11:12:00 +0100 Subject: [PATCH 02/16] [dev-menu] update labels and icons for consistency (#42825) # Why This PR updates the labels in the developer menu for better consistency across platforms. It renames "JS debugger" to "DevTools" and makes other label adjustments to provide a more unified experience. # How - Changed a couple of labels - updated dev tools icon - Updated documentation to reflect these label changes - Removed unused string resources from Android strings.xml # Test Plan - tested locally, green CI # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) --- .../expoview/src/main/res/values/strings.xml | 13 ------------- .../Versioned/Core/EXVersionManagerObjC.mm | 2 +- docs/pages/debugging/tools.mdx | 2 +- docs/pages/guides/using-hermes.mdx | 2 +- guides/releasing/Quality Assurance.md | 2 +- packages/expo-dev-menu/CHANGELOG.md | 2 ++ .../modules/devmenu/compose/ui/MenuIcons.kt | 6 +++--- .../modules/devmenu/compose/ui/ToolsSection.kt | 10 +++++----- .../android/src/debug/res/drawable/bug.xml | 16 ---------------- .../src/debug/res/drawable/code_brackets.xml | 18 ++++++++++++++++++ .../expo-dev-menu/ios/FAB/DevMenuFABView.swift | 2 +- .../ios/SwiftUI/DevMenuDeveloperTools.swift | 8 ++++---- 12 files changed, 37 insertions(+), 46 deletions(-) delete mode 100644 packages/expo-dev-menu/android/src/debug/res/drawable/bug.xml create mode 100644 packages/expo-dev-menu/android/src/debug/res/drawable/code_brackets.xml 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/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/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-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 From 97c65586874f58bdfe1741a6ee5b1a3cfef1cc36 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 16 Feb 2026 12:15:49 +0000 Subject: [PATCH 03/16] fix(expo-server): Only use `request.url` for `origin` in development and properly default to `null` (#43143) # Why We accidentally had the `|| null` fallback for `origin` in the environment values, rather than only in the last `origin()` call. This matched `globalThis.origin` (which also has this default) but not the `origin()` API convention. We also used the `Origin` header in development environments, which isn't guaranteed to be present. We assume development has no request forwarding that's relevant to us, so we can always use `request.url` instead. **This shouldn't be backported to SDK 54 as it's technically a breaking change.** # How - Switch to `request.url` for deriving `origin` in development (node and workerd adapters) - Fix `origin` type in `RequestAPI` to allow `null` - Remove `|| 'null'` for `|| null` defaults in adapters # Test Plan - n/a # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- .../@expo/cli/e2e/__tests__/export/server.test.ts | 2 +- packages/expo-server/CHANGELOG.md | 1 + packages/expo-server/build/cjs/runtime/api.d.ts | 7 ++++--- packages/expo-server/build/cjs/runtime/api.js | 7 ++++--- packages/expo-server/build/cjs/runtime/api.js.map | 2 +- packages/expo-server/build/cjs/runtime/index.d.ts | 2 +- packages/expo-server/build/cjs/runtime/index.js | 4 +++- packages/expo-server/build/cjs/runtime/index.js.map | 2 +- packages/expo-server/build/cjs/runtime/scope.d.ts | 2 +- packages/expo-server/build/cjs/vendor/eas.js | 2 +- packages/expo-server/build/cjs/vendor/eas.js.map | 2 +- .../expo-server/build/cjs/vendor/environment/node.js | 11 ++++++++++- .../build/cjs/vendor/environment/node.js.map | 2 +- .../build/cjs/vendor/environment/workerd.js | 11 ++++++++++- .../build/cjs/vendor/environment/workerd.js.map | 2 +- packages/expo-server/build/cjs/vendor/netlify.js | 2 +- packages/expo-server/build/cjs/vendor/netlify.js.map | 2 +- packages/expo-server/build/cjs/vendor/vercel.js | 2 +- packages/expo-server/build/cjs/vendor/vercel.js.map | 2 +- packages/expo-server/build/mjs/runtime/api.d.ts | 7 ++++--- packages/expo-server/build/mjs/runtime/api.js | 7 ++++--- packages/expo-server/build/mjs/runtime/api.js.map | 2 +- packages/expo-server/build/mjs/runtime/index.d.ts | 2 +- packages/expo-server/build/mjs/runtime/index.js | 4 +++- packages/expo-server/build/mjs/runtime/index.js.map | 2 +- packages/expo-server/build/mjs/runtime/scope.d.ts | 2 +- packages/expo-server/build/mjs/vendor/eas.js | 2 +- packages/expo-server/build/mjs/vendor/eas.js.map | 2 +- .../expo-server/build/mjs/vendor/environment/node.js | 11 ++++++++++- .../build/mjs/vendor/environment/node.js.map | 2 +- .../build/mjs/vendor/environment/workerd.js | 11 ++++++++++- .../build/mjs/vendor/environment/workerd.js.map | 2 +- packages/expo-server/build/mjs/vendor/netlify.js | 2 +- packages/expo-server/build/mjs/vendor/netlify.js.map | 2 +- packages/expo-server/build/mjs/vendor/vercel.js | 2 +- packages/expo-server/build/mjs/vendor/vercel.js.map | 2 +- packages/expo-server/src/runtime/api.ts | 7 ++++--- packages/expo-server/src/runtime/index.ts | 6 ++++-- packages/expo-server/src/runtime/scope.ts | 2 +- packages/expo-server/src/vendor/eas.ts | 2 +- packages/expo-server/src/vendor/environment/node.ts | 11 ++++++++++- .../expo-server/src/vendor/environment/workerd.ts | 11 ++++++++++- packages/expo-server/src/vendor/netlify.ts | 2 +- packages/expo-server/src/vendor/vercel.ts | 2 +- 44 files changed, 120 insertions(+), 54 deletions(-) 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-server/CHANGELOG.md b/packages/expo-server/CHANGELOG.md index dcfa1c665dfe95..7e3d192cc309ef 100644 --- a/packages/expo-server/CHANGELOG.md +++ b/packages/expo-server/CHANGELOG.md @@ -10,6 +10,7 @@ - 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 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.js b/packages/expo-server/build/cjs/vendor/eas.js index ae237a40e9aedb..82849b74e499a1 100644 --- a/packages/expo-server/build/cjs/vendor/eas.js +++ b/packages/expo-server/build/cjs/vendor/eas.js @@ -14,7 +14,7 @@ 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), }); diff --git a/packages/expo-server/build/cjs/vendor/eas.js.map b/packages/expo-server/build/cjs/vendor/eas.js.map index 8a5e8e8c233809..9c21559a08d02a 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":";;;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,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,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 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..90c8a81d940f4a 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,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,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.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..9d235ff9becace 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":"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"} \ 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.js b/packages/expo-server/build/mjs/vendor/eas.js index 04af3733d3c03d..e4abacbe8940e1 100644 --- a/packages/expo-server/build/mjs/vendor/eas.js +++ b/packages/expo-server/build/mjs/vendor/eas.js @@ -9,7 +9,7 @@ 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), }); diff --git a/packages/expo-server/build/mjs/vendor/eas.js.map b/packages/expo-server/build/mjs/vendor/eas.js.map index 0d694e8d78b4e9..6dfe471238843b 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;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,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,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 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..7fe31d941b59d4 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,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,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.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..8be67d410f9ee5 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":"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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/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/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..2c277df14f17fc 100644 --- a/packages/expo-server/src/vendor/eas.ts +++ b/packages/expo-server/src/vendor/eas.ts @@ -22,7 +22,7 @@ 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), }); diff --git a/packages/expo-server/src/vendor/environment/node.ts b/packages/expo-server/src/vendor/environment/node.ts index 3f6a0d31dfa1ff..1a98c1819fbddd 100644 --- a/packages/expo-server/src/vendor/environment/node.ts +++ b/packages/expo-server/src/vendor/environment/node.ts @@ -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..22029f9bbbd05b 100644 --- a/packages/expo-server/src/vendor/environment/workerd.ts +++ b/packages/expo-server/src/vendor/environment/workerd.ts @@ -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, From e3db8b7d6e1851c4c3b32f6541feaa74ec2298a3 Mon Sep 17 00:00:00 2001 From: Wiktor Smaga Date: Mon, 16 Feb 2026 13:30:16 +0100 Subject: [PATCH 04/16] [ci] Ignore web files in Test Suite e2e (#43168) # Why Changes to `*.web.*` files do not affect Android and iOS builds, so they shouldn't trigger the test suite E2E. This is the case here: https://github.com/expo/expo/pull/43153 # How Add `**/*.web.*` to `shared-ignores`. List of affected files: [web.txt](https://github.com/user-attachments/files/25339421/web.txt) # Test Plan Tested on a stacked PR. --- .github/actions/detect-platform-change/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From 6f43406710b560bcc1731219b7e6e69f4d2caf8b Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Mon, 16 Feb 2026 12:31:26 +0000 Subject: [PATCH 05/16] [web][audio]Enable audio sampling (#43149) # Why Part of a PR stack the brings more feature parity between web and native Adds audio sampling on web # How Web has good support for this using `AnalyserNode` # Test Plan Bare expo --- .../src/screens/Audio/AudioPlayer.tsx | 10 +- .../src/screens/Audio/AudioPlayerScreen.tsx | 1 + .../src/screens/Audio/JsiAudioBar.tsx | 6 +- packages/expo-audio/CHANGELOG.md | 1 + .../expo-audio/build/AudioModule.web.d.ts | 5 + .../expo-audio/build/AudioModule.web.d.ts.map | 2 +- packages/expo-audio/build/AudioModule.web.js | 94 ++++++++++++++- .../expo-audio/build/AudioModule.web.js.map | 2 +- packages/expo-audio/src/AudioModule.web.ts | 114 +++++++++++++++++- 9 files changed, 224 insertions(+), 11 deletions(-) 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/packages/expo-audio/CHANGELOG.md b/packages/expo-audio/CHANGELOG.md index 53cc410f7e549c..d4ed8640faf095 100644 --- a/packages/expo-audio/CHANGELOG.md +++ b/packages/expo-audio/CHANGELOG.md @@ -8,6 +8,7 @@ - [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. ### 🐛 Bug fixes diff --git a/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index 9164c38ab47e88..f8f5f68dd344db 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -13,6 +13,10 @@ export declare class AudioPlayerWeb extends globalThis.expo.SharedObject): void; updateLockScreenMetadata(metadata: Record): void; clearLockScreenControls(): void; + _isCrossOrigin(): boolean; _createMediaElement(): HTMLAudioElement; } export declare class AudioRecorderWeb extends globalThis.expo.SharedObject implements AudioRecorder { diff --git a/packages/expo-audio/build/AudioModule.web.d.ts.map b/packages/expo-audio/build/AudioModule.web.d.ts.map index 0d663b084cd834..e6181755a58eba 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":"AACA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EACL,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,gBAAgB,EAEhB,qBAAqB,EACtB,MAAM,eAAe,CAAC;AAMvB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAgG/F,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;IAsB5B,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;IAMtF,MAAM,IAAI,IAAI;IAuBd,sBAAsB,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAC5E,wBAAwB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAC7D,uBAAuB,IAAI,IAAI;IAE/B,cAAc,IAAI,OAAO;IAQzB,mBAAmB,IAAI,gBAAgB;CA6DxC;AAkBD,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;IAElC,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;IAQpC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3C,SAAS,IAAI,aAAa;IAW1B,KAAK,IAAI,IAAI;IAUb,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIxC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAE7B,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIrC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B,aAAa;YAIC,mBAAmB;IAyDjC,OAAO,CAAC,8BAA8B;CAOvC;AAED,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..ac78dac6e18ef0 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -1,11 +1,18 @@ import { Asset } from 'expo-asset'; import { PermissionStatus } from 'expo-modules-core'; -import { PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE } from './AudioEventKeys'; +import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE, } from './AudioEventKeys'; import { RecordingPresets } from './RecordingConstants'; const nextId = (() => { let id = 0; return () => id++; })(); +let audioContext = null; +function getAudioContext() { + if (!audioContext) { + audioContext = new AudioContext(); + } + return audioContext; +} async function getPermissionWithQueryAsync(name) { if (!navigator || !navigator.permissions || !navigator.permissions.query) return null; @@ -93,6 +100,10 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { isPlaying = false; loaded = false; crossOrigin; + analyser = null; + sourceNode = null; + samplingFrameId = null; + samplingEnabled = false; get playing() { return this.isPlaying; } @@ -145,12 +156,16 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { } replace(source) { const wasPlaying = this.isPlaying; + const wasSampling = this.samplingEnabled; // 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); + } // Resume playback if it was playing before if (wasPlaying) { this.play(); @@ -159,9 +174,61 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { async seekTo(seconds, toleranceMillisBefore, toleranceMillisAfter) { this.media.currentTime = seconds; } - // Not supported on web setAudioSamplingEnabled(enabled) { - this.isAudioSamplingSupported = false; + 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; @@ -169,6 +236,19 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { this.media.preservesPitch = this.shouldCorrectPitch; } remove() { + 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(); @@ -177,6 +257,14 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { setActiveForLockScreen(active, metadata) { } updateLockScreenMetadata(metadata) { } clearLockScreenControls() { } + _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); diff --git a/packages/expo-audio/build/AudioModule.web.js.map b/packages/expo-audio/build/AudioModule.web.js.map index 535c047ccfc98f..a4fb9e5eb061c8 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":"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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 {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} 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\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 // 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 }\n\n remove(): void {\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(active: boolean, metadata: Record): void {}\n updateLockScreenMetadata(metadata: Record): void {}\n clearLockScreenControls(): void {}\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 }\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 diff --git a/packages/expo-audio/src/AudioModule.web.ts b/packages/expo-audio/src/AudioModule.web.ts index b18c25cb1ebc64..650dcdb41acc5c 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -13,7 +13,11 @@ import { RecordingOptionsWeb, RecordingStartOptions, } from './Audio.types'; -import { PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE } from './AudioEventKeys'; +import { + AUDIO_SAMPLE_UPDATE, + PLAYBACK_STATUS_UPDATE, + RECORDING_STATUS_UPDATE, +} from './AudioEventKeys'; import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; import { RecordingPresets } from './RecordingConstants'; @@ -22,6 +26,15 @@ const nextId = (() => { return () => id++; })(); +let audioContext: AudioContext | null = null; + +function getAudioContext(): AudioContext { + if (!audioContext) { + audioContext = new AudioContext(); + } + return audioContext; +} + async function getPermissionWithQueryAsync( name: PermissionNameWithAdditionalValues ): Promise { @@ -125,6 +138,10 @@ export class AudioPlayerWeb 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; @@ -194,6 +211,7 @@ export class AudioPlayerWeb replace(source: AudioSource): void { const wasPlaying = this.isPlaying; + const wasSampling = this.samplingEnabled; // we need to remove the current media element and create a new one this.remove(); @@ -203,6 +221,10 @@ export class AudioPlayerWeb this.loaded = false; this.media = this._createMediaElement(); + if (wasSampling) { + this.setAudioSamplingEnabled(true); + } + // Resume playback if it was playing before if (wasPlaying) { this.play(); @@ -217,9 +239,71 @@ export class AudioPlayerWeb this.media.currentTime = seconds; } - // Not supported on web setAudioSamplingEnabled(enabled: boolean): void { - this.isAudioSamplingSupported = false; + 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 { @@ -229,6 +313,22 @@ export class AudioPlayerWeb } remove(): void { + 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(); @@ -239,6 +339,14 @@ export class AudioPlayerWeb updateLockScreenMetadata(metadata: Record): void {} clearLockScreenControls(): void {} + _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); From 85bb06c68937eeaee4db6ce185a28c6ad05ec107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Dr=C3=B3=C5=BCd=C5=BC?= <31368152+behenate@users.noreply.github.com> Date: Mon, 16 Feb 2026 13:33:14 +0100 Subject: [PATCH 06/16] [audio][2/2] - Rework foreground service handling - native Android changes (#43015) # Why I wanted to add clear errors if the plugin is misconfigured due to changes introduced in :https://github.com/expo/expo/pull/43014 , but I've found it impossible to actually detect if the service has successfully started with the current singleton-based implementation for some reason. # How - Migrate to having a separate Recodring and playback services - Use the pattern of having a single service and multiple service connections and bindings - Add errors if the plugin is misconfigured - Try connecting to the service in the recording preparation, if connection fails throw an error - For the controls service, we don't have the luxury of having an async function to wait to connect to the service, so we start the playback and update the service once it connects. If it fails we use the jsLogger to send a visible non-fatal error to developers # Test Plan Tested in prebuilt NCL on Android --- packages/expo-audio/CHANGELOG.md | 1 + .../expo/modules/audio/AudioExceptions.kt | 35 +++ .../java/expo/modules/audio/AudioModule.kt | 6 +- .../java/expo/modules/audio/AudioPlayer.kt | 56 +++- .../java/expo/modules/audio/AudioRecorder.kt | 75 +++-- .../java/expo/modules/audio/AudioUtils.kt | 9 + .../audio/service/AudioControlsService.kt | 270 ++++++++++-------- .../service/AudioPlaybackServiceConnection.kt | 100 +++++++ .../audio/service/AudioRecordingService.kt | 127 ++++---- .../AudioRecordingServiceConnection.kt | 153 ++++++++++ .../audio/service/BaseServiceConnection.kt | 141 +++++++++ 11 files changed, 755 insertions(+), 218 deletions(-) create mode 100644 packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioPlaybackServiceConnection.kt create mode 100644 packages/expo-audio/android/src/main/java/expo/modules/audio/service/AudioRecordingServiceConnection.kt create mode 100644 packages/expo-audio/android/src/main/java/expo/modules/audio/service/BaseServiceConnection.kt diff --git a/packages/expo-audio/CHANGELOG.md b/packages/expo-audio/CHANGELOG.md index d4ed8640faf095..9c5497042f7c80 100644 --- a/packages/expo-audio/CHANGELOG.md +++ b/packages/expo-audio/CHANGELOG.md @@ -18,6 +18,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 + } + } +} From 6c193fe5476558398cf39ff040b773c2d726cfb4 Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Mon, 16 Feb 2026 12:33:32 +0000 Subject: [PATCH 07/16] [web][audio] Support media controls (#43150) # Why Part of a PR stack the brings more feature parity between web and native Adds media controls on web # How Screenshot 2026-02-14 at 10 52 44 Screenshot 2026-02-14 at 10 38 33 # Test Plan Bare expo --- .../expo-audio/build/AudioModule.web.d.ts | 7 +- .../expo-audio/build/AudioModule.web.d.ts.map | 2 +- packages/expo-audio/build/AudioModule.web.js | 32 ++- .../expo-audio/build/AudioModule.web.js.map | 2 +- .../build/MediaSessionController.web.d.ts | 32 +++ .../build/MediaSessionController.web.d.ts.map | 1 + .../build/MediaSessionController.web.js | 156 ++++++++++++++ .../build/MediaSessionController.web.js.map | 1 + packages/expo-audio/src/AudioModule.web.ts | 45 ++++- .../src/MediaSessionController.web.ts | 191 ++++++++++++++++++ 10 files changed, 458 insertions(+), 11 deletions(-) create mode 100644 packages/expo-audio/build/MediaSessionController.web.d.ts create mode 100644 packages/expo-audio/build/MediaSessionController.web.d.ts.map create mode 100644 packages/expo-audio/build/MediaSessionController.web.js create mode 100644 packages/expo-audio/build/MediaSessionController.web.js.map create mode 100644 packages/expo-audio/src/MediaSessionController.web.ts diff --git a/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index f8f5f68dd344db..9f04fdb25a36de 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -1,5 +1,6 @@ import { PermissionResponse } from 'expo-modules-core'; -import { AudioMode, AudioPlayerOptions, AudioSource, AudioStatus, PitchCorrectionQuality, RecorderState, RecordingInput, RecordingOptions, RecordingStartOptions } from './Audio.types'; +import { AudioMetadata, AudioMode, AudioPlayerOptions, AudioSource, AudioStatus, PitchCorrectionQuality, RecorderState, RecordingInput, RecordingOptions, RecordingStartOptions } from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; export declare class AudioPlayerWeb extends globalThis.expo.SharedObject implements AudioPlayer { constructor(source: AudioSource, options?: AudioPlayerOptions); @@ -38,8 +39,8 @@ export declare class AudioPlayerWeb extends globalThis.expo.SharedObject): void; - updateLockScreenMetadata(metadata: Record): void; + setActiveForLockScreen(active: boolean, metadata?: AudioMetadata, options?: AudioLockScreenOptions): void; + updateLockScreenMetadata(metadata: AudioMetadata): void; clearLockScreenControls(): void; _isCrossOrigin(): boolean; _createMediaElement(): HTMLAudioElement; diff --git a/packages/expo-audio/build/AudioModule.web.d.ts.map b/packages/expo-audio/build/AudioModule.web.d.ts.map index e6181755a58eba..72a09366868ff2 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":"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"} \ 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 ac78dac6e18ef0..6963a9dd19adce 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -1,6 +1,7 @@ import { Asset } from 'expo-asset'; import { PermissionStatus } from 'expo-modules-core'; import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE, } from './AudioEventKeys'; +import { mediaSessionController } from './MediaSessionController.web'; import { RecordingPresets } from './RecordingConstants'; const nextId = (() => { let id = 0; @@ -157,6 +158,7 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { 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; @@ -166,6 +168,9 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { 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(); @@ -234,8 +239,10 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { 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; @@ -254,9 +261,20 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { this.media.load(); getStatusFromMedia(this.media, this.id); } - setActiveForLockScreen(active, metadata) { } - updateLockScreenMetadata(metadata) { } - clearLockScreenControls() { } + 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; @@ -283,6 +301,7 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { if (now - lastEmitTime >= intervalSec) { lastEmitTime = now; this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); } }; media.onplay = () => { @@ -292,6 +311,8 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { ...getStatusFromMedia(media, this.id), playing: this.isPlaying, }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); }; media.onpause = () => { this.isPlaying = false; @@ -300,13 +321,17 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { ...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; @@ -315,6 +340,7 @@ export class AudioPlayerWeb extends globalThis.expo.SharedObject { ...getStatusFromMedia(media, this.id), isLoaded: this.loaded, }); + mediaSessionController.updatePositionState(this); }; return media; } diff --git a/packages/expo-audio/build/AudioModule.web.js.map b/packages/expo-audio/build/AudioModule.web.js.map index a4fb9e5eb061c8..72b86918f51883 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 {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} 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\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 // 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 }\n\n remove(): void {\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(active: boolean, metadata: Record): void {}\n updateLockScreenMetadata(metadata: Record): void {}\n clearLockScreenControls(): void {}\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 }\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":"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","sourcesContent":["import { Asset } from 'expo-asset';\nimport { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport {\n AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 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 650dcdb41acc5c..d024a536202cf5 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -2,6 +2,7 @@ import { Asset } from 'expo-asset'; import { PermissionResponse, PermissionStatus } from 'expo-modules-core'; import { + AudioMetadata, AudioMode, AudioPlayerOptions, AudioSource, @@ -13,12 +14,14 @@ import { RecordingOptionsWeb, RecordingStartOptions, } from './Audio.types'; +import { AudioLockScreenOptions } from './AudioConstants'; import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE, } from './AudioEventKeys'; import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; +import { mediaSessionController } from './MediaSessionController.web'; import { RecordingPresets } from './RecordingConstants'; const nextId = (() => { @@ -212,6 +215,7 @@ export class AudioPlayerWeb 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(); @@ -225,6 +229,14 @@ export class AudioPlayerWeb 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(); @@ -310,9 +322,12 @@ export class AudioPlayerWeb 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; @@ -335,9 +350,25 @@ export class AudioPlayerWeb getStatusFromMedia(this.media, this.id); } - setActiveForLockScreen(active: boolean, metadata: Record): void {} - updateLockScreenMetadata(metadata: Record): void {} - clearLockScreenControls(): void {} + 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 { @@ -367,6 +398,7 @@ export class AudioPlayerWeb if (now - lastEmitTime >= intervalSec) { lastEmitTime = now; this.emit(PLAYBACK_STATUS_UPDATE, getStatusFromMedia(media, this.id)); + mediaSessionController.updatePositionState(this); } }; @@ -377,6 +409,8 @@ export class AudioPlayerWeb ...getStatusFromMedia(media, this.id), playing: this.isPlaying, }); + mediaSessionController.updatePlaybackState(this); + mediaSessionController.updatePositionState(this); }; media.onpause = () => { @@ -386,15 +420,19 @@ export class AudioPlayerWeb ...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 = () => { @@ -404,6 +442,7 @@ export class AudioPlayerWeb ...getStatusFromMedia(media, this.id), isLoaded: this.loaded, }); + mediaSessionController.updatePositionState(this); }; return media; 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(); From e4579db2713fbb9a893044af6829379942abf50f Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Mon, 16 Feb 2026 12:35:34 +0000 Subject: [PATCH 08/16] [web][audio] Support selecting recording inputs (#43151) # Why Part of a PR stack the brings more feature parity between web and native Adds selecting the recording input on web # How Access `navigator.mediaDevices` to get the list of available devices # Test Plan Bare expo --- .../src/screens/Audio/AudioInputSelector.tsx | 5 +- .../src/screens/Audio/Recorder.tsx | 2 +- .../expo-audio/build/AudioModule.web.d.ts | 5 ++ .../expo-audio/build/AudioModule.web.d.ts.map | 2 +- packages/expo-audio/build/AudioModule.web.js | 46 ++++++++++++-- .../expo-audio/build/AudioModule.web.js.map | 2 +- packages/expo-audio/src/AudioModule.web.ts | 61 ++++++++++++++++--- 7 files changed, 106 insertions(+), 17 deletions(-) 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/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/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index 9f04fdb25a36de..c46421f40a4f96 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -56,6 +56,10 @@ export declare class AudioRecorderWeb extends globalThis.expo.SharedObject; clearTimeouts(): void; private createMediaRecorder; + private updateCachedInputs; private getAudioRecorderDurationMillis; } export declare function setAudioModeAsync(mode: AudioMode): Promise; diff --git a/packages/expo-audio/build/AudioModule.web.d.ts.map b/packages/expo-audio/build/AudioModule.web.d.ts.map index 72a09366868ff2..0638ceac63f446 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":"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"} \ 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 6963a9dd19adce..9fcefd5ef036ac 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -375,6 +375,10 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { mediaRecorderUptimeOfLastStartResume = 0; mediaRecorderIsRecording = false; timeoutIds = []; + cachedInputs = []; + selectedDeviceId = null; + stream = null; + handleDeviceChange = null; get isRecording() { return this.mediaRecorder?.state === 'recording'; } @@ -403,10 +407,15 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { } } getAvailableInputs() { - return []; + return this.cachedInputs; } getCurrentInput() { - return Promise.resolve({ + 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', @@ -433,7 +442,12 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { recordForDuration(seconds) { this.record({ forDuration: seconds }); } - setInput(input) { } + 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 }); } @@ -464,7 +478,16 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { } this.mediaRecorderUptimeOfLastStartResume = 0; this.currentTime = 0; - const stream = await getUserMedia({ audio: true }); + 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); const defaults = RecordingPresets.HIGH_QUALITY.web; const mediaRecorderOptions = {}; const mimeType = options.mimeType ?? defaults.mimeType; @@ -497,11 +520,26 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { mediaRecorder?.addEventListener('stop', () => { this.currentTime = 0; this.mediaRecorderIsRecording = false; + this.stream = 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', + })); + } getAudioRecorderDurationMillis() { let duration = this.currentTime; if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { diff --git a/packages/expo-audio/build/AudioModule.web.js.map b/packages/expo-audio/build/AudioModule.web.js.map index 72b86918f51883..d4e5ccf73f2754 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 AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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":"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","sourcesContent":["import { Asset } from 'expo-asset';\nimport { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport {\n AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 private cachedInputs: RecordingInput[] = [];\n private selectedDeviceId: string | null = null;\n private stream: MediaStream | null = null;\n private handleDeviceChange: (() => void) | null = null;\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 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 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 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.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 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 diff --git a/packages/expo-audio/src/AudioModule.web.ts b/packages/expo-audio/src/AudioModule.web.ts index d024a536202cf5..1ae7f6eb3631b6 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -487,6 +487,10 @@ export class AudioRecorderWeb 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; get isRecording(): boolean { return this.mediaRecorder?.state === 'recording'; @@ -526,15 +530,23 @@ export class AudioRecorderWeb } getAvailableInputs(): RecordingInput[] { - return []; + return this.cachedInputs; } getCurrentInput(): Promise { - return Promise.resolve({ - type: 'Default', - name: 'Default', - uid: 'Default', - }); + 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 { @@ -566,7 +578,12 @@ export class AudioRecorderWeb this.record({ forDuration: seconds }); } - setInput(input: string): void {} + 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 }); @@ -614,7 +631,18 @@ export class AudioRecorderWeb this.mediaRecorderUptimeOfLastStartResume = 0; this.currentTime = 0; - const stream = await getUserMedia({ audio: true }); + 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); const defaults = RecordingPresets.HIGH_QUALITY.web; const mediaRecorderOptions: MediaRecorderOptions = {}; @@ -653,6 +681,12 @@ export class AudioRecorderWeb mediaRecorder?.addEventListener('stop', () => { this.currentTime = 0; this.mediaRecorderIsRecording = false; + this.stream = 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()); @@ -661,6 +695,17 @@ export class AudioRecorderWeb 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', + })); + } + private getAudioRecorderDurationMillis() { let duration = this.currentTime; if (this.mediaRecorderIsRecording && this.mediaRecorderUptimeOfLastStartResume > 0) { From 08d3fe2682bb3c88cda59cc0a69e0aa0855ca89b Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Mon, 16 Feb 2026 12:37:41 +0000 Subject: [PATCH 09/16] [web][audio] Support metering (#43152) # Why Part of a PR stack the brings more feature parity between web and native Adds metering support for recordings on web # How Similar to sampling, we can do this with an `AnalyserNode`. We use the same algorithm we do on native in `getMeteringLevel()` # Test Plan Bare expo --- .../expo-audio/build/AudioModule.web.d.ts | 5 ++ .../expo-audio/build/AudioModule.web.d.ts.map | 2 +- packages/expo-audio/build/AudioModule.web.js | 48 ++++++++++++++++- .../expo-audio/build/AudioModule.web.js.map | 2 +- packages/expo-audio/src/AudioModule.web.ts | 51 ++++++++++++++++++- 5 files changed, 104 insertions(+), 4 deletions(-) diff --git a/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index c46421f40a4f96..7ca3ffd72f4c94 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -60,6 +60,10 @@ export declare class AudioRecorderWeb extends globalThis.expo.SharedObject; diff --git a/packages/expo-audio/build/AudioModule.web.d.ts.map b/packages/expo-audio/build/AudioModule.web.d.ts.map index 0638ceac63f446..c6ad2c12b34888 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":"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"} \ 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 9fcefd5ef036ac..e72d81ba34a37f 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -379,6 +379,10 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { selectedDeviceId = null; stream = null; handleDeviceChange = null; + analyser = null; + analyserBuffer = null; + analyserSource = null; + meteringEnabled = false; get isRecording() { return this.mediaRecorder?.state === 'recording'; } @@ -425,13 +429,17 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { return this.setup(); } getStatus() { - return { + 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) { @@ -488,6 +496,18 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { 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; @@ -521,6 +541,15 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { 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; @@ -540,6 +569,23 @@ export class AudioRecorderWeb extends globalThis.expo.SharedObject { 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) { diff --git a/packages/expo-audio/build/AudioModule.web.js.map b/packages/expo-audio/build/AudioModule.web.js.map index d4e5ccf73f2754..9b6dbc4b975f71 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 AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 private cachedInputs: RecordingInput[] = [];\n private selectedDeviceId: string | null = null;\n private stream: MediaStream | null = null;\n private handleDeviceChange: (() => void) | null = null;\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 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 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 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.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 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":"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","sourcesContent":["import { Asset } from 'expo-asset';\nimport { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport {\n AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 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\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/src/AudioModule.web.ts b/packages/expo-audio/src/AudioModule.web.ts index 1ae7f6eb3631b6..5ba3529d6fe6bb 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -491,6 +491,10 @@ export class AudioRecorderWeb 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'; @@ -554,7 +558,7 @@ export class AudioRecorderWeb } getStatus(): RecorderState { - return { + const status: RecorderState = { canRecord: this.mediaRecorder?.state === 'recording' || this.mediaRecorder?.state === 'inactive', isRecording: this.mediaRecorder?.state === 'recording', @@ -562,6 +566,10 @@ export class AudioRecorderWeb mediaServicesDidReset: false, url: this.uri, }; + if (this.meteringEnabled && this.mediaRecorderIsRecording) { + status.metering = this.getMeteringLevel(); + } + return status; } pause(): void { @@ -644,6 +652,19 @@ export class AudioRecorderWeb }; 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 = {}; @@ -683,6 +704,16 @@ export class AudioRecorderWeb 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; @@ -706,6 +737,24 @@ export class AudioRecorderWeb })); } + // 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) { From 8f104da2373e5c8fa9c132810f00530640c79113 Mon Sep 17 00:00:00 2001 From: Alan Hughes <30924086+alanjhughes@users.noreply.github.com> Date: Mon, 16 Feb 2026 12:39:36 +0000 Subject: [PATCH 10/16] [web][audio] Refactor large web file (#43153) # Why `AudioPlayer.web` has gotten huge. # How Refactor player, recorder and utils into separate files. # Test Plan Bare expo --- packages/expo-audio/CHANGELOG.md | 5 +- .../expo-audio/build/AudioModule.web.d.ts | 86 +- .../expo-audio/build/AudioModule.web.d.ts.map | 2 +- packages/expo-audio/build/AudioModule.web.js | 579 +------------- .../expo-audio/build/AudioModule.web.js.map | 2 +- .../expo-audio/build/AudioPlayer.web.d.ts | 47 ++ .../expo-audio/build/AudioPlayer.web.d.ts.map | 1 + packages/expo-audio/build/AudioPlayer.web.js | 267 +++++++ .../expo-audio/build/AudioPlayer.web.js.map | 1 + .../expo-audio/build/AudioRecorder.web.d.ts | 40 + .../build/AudioRecorder.web.d.ts.map | 1 + .../expo-audio/build/AudioRecorder.web.js | 239 ++++++ .../expo-audio/build/AudioRecorder.web.js.map | 1 + packages/expo-audio/build/AudioUtils.web.d.ts | 7 + .../expo-audio/build/AudioUtils.web.d.ts.map | 1 + packages/expo-audio/build/AudioUtils.web.js | 76 ++ .../expo-audio/build/AudioUtils.web.js.map | 1 + packages/expo-audio/src/AudioModule.web.ts | 745 +----------------- packages/expo-audio/src/AudioPlayer.web.ts | 344 ++++++++ packages/expo-audio/src/AudioRecorder.web.ts | 310 ++++++++ packages/expo-audio/src/AudioUtils.web.ts | 91 +++ 21 files changed, 1443 insertions(+), 1403 deletions(-) create mode 100644 packages/expo-audio/build/AudioPlayer.web.d.ts create mode 100644 packages/expo-audio/build/AudioPlayer.web.d.ts.map create mode 100644 packages/expo-audio/build/AudioPlayer.web.js create mode 100644 packages/expo-audio/build/AudioPlayer.web.js.map create mode 100644 packages/expo-audio/build/AudioRecorder.web.d.ts create mode 100644 packages/expo-audio/build/AudioRecorder.web.d.ts.map create mode 100644 packages/expo-audio/build/AudioRecorder.web.js create mode 100644 packages/expo-audio/build/AudioRecorder.web.js.map create mode 100644 packages/expo-audio/build/AudioUtils.web.d.ts create mode 100644 packages/expo-audio/build/AudioUtils.web.d.ts.map create mode 100644 packages/expo-audio/build/AudioUtils.web.js create mode 100644 packages/expo-audio/build/AudioUtils.web.js.map create mode 100644 packages/expo-audio/src/AudioPlayer.web.ts create mode 100644 packages/expo-audio/src/AudioRecorder.web.ts create mode 100644 packages/expo-audio/src/AudioUtils.web.ts diff --git a/packages/expo-audio/CHANGELOG.md b/packages/expo-audio/CHANGELOG.md index 9c5497042f7c80..4dea42b08ae661 100644 --- a/packages/expo-audio/CHANGELOG.md +++ b/packages/expo-audio/CHANGELOG.md @@ -8,7 +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. +- [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 diff --git a/packages/expo-audio/build/AudioModule.web.d.ts b/packages/expo-audio/build/AudioModule.web.d.ts index 7ca3ffd72f4c94..469905e3de532a 100644 --- a/packages/expo-audio/build/AudioModule.web.d.ts +++ b/packages/expo-audio/build/AudioModule.web.d.ts @@ -1,87 +1,7 @@ import { PermissionResponse } from 'expo-modules-core'; -import { AudioMetadata, AudioMode, AudioPlayerOptions, AudioSource, AudioStatus, PitchCorrectionQuality, RecorderState, RecordingInput, RecordingOptions, RecordingStartOptions } from './Audio.types'; -import { AudioLockScreenOptions } from './AudioConstants'; -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?; - 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; -} -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; -} +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 c6ad2c12b34888..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":"AACA,OAAO,EAAE,kBAAkB,EAAoB,MAAM,mBAAmB,CAAC;AAEzE,OAAO,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,gBAAgB,EAEhB,qBAAqB,EACtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAM1D,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAiG/F,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;AAkBD,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;AAED,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 +{"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 e72d81ba34a37f..bb01e60afd32e7 100644 --- a/packages/expo-audio/build/AudioModule.web.js +++ b/packages/expo-audio/build/AudioModule.web.js @@ -1,19 +1,7 @@ -import { Asset } from 'expo-asset'; import { PermissionStatus } from 'expo-modules-core'; -import { AUDIO_SAMPLE_UPDATE, PLAYBACK_STATUS_UPDATE, RECORDING_STATUS_UPDATE, } from './AudioEventKeys'; -import { mediaSessionController } from './MediaSessionController.web'; -import { RecordingPresets } from './RecordingConstants'; -const nextId = (() => { - let id = 0; - return () => id++; -})(); -let audioContext = null; -function getAudioContext() { - if (!audioContext) { - audioContext = new AudioContext(); - } - return audioContext; -} +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; @@ -33,567 +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; - 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; - } -} -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 = []; - 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; - } -} 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 9b6dbc4b975f71..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":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAgBzE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE;IACnB,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,SAAS,eAAe;IACtB,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,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,SAAS,YAAY,CAAC,WAAmC;IACvD,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,SAAS,kBAAkB,CAAC,KAAuB,EAAE,EAAU;IAC7D,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,OAAO,cACX,SAAQ,UAAU,CAAC,IAAI,CAAC,YAAyB;IAGjD,YAAY,MAAmB,EAAE,UAA8B,EAAE;QAC/D,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,cAAc,GAAG,GAAG,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QACtD,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC;QAC5C,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;IAC1C,CAAC;IAED,EAAE,GAAW,MAAM,EAAE,CAAC;IACtB,wBAAwB,GAAG,KAAK,CAAC;IACjC,WAAW,GAAG,KAAK,CAAC;IACpB,kBAAkB,GAAG,KAAK,CAAC;IAEnB,GAAG,GAAgB,IAAI,CAAC;IACxB,KAAK,CAAmB;IACxB,QAAQ,GAAG,GAAG,CAAC;IACf,SAAS,GAAG,KAAK,CAAC;IAClB,MAAM,GAAG,KAAK,CAAC;IACf,WAAW,CAAmC;IAC9C,QAAQ,GAAwB,IAAI,CAAC;IACrC,UAAU,GAAuC,IAAI,CAAC;IACtD,eAAe,GAAkB,IAAI,CAAC;IACtC,eAAe,GAAG,KAAK,CAAC;IAEhC,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;IAED,IAAI,KAAK,CAAC,KAAc;QACtB,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,IAAI,CAAC,KAAc;QACrB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC;IAC1B,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;IAChC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;IACjC,CAAC;IAED,IAAI,YAAY,CAAC,KAAa;QAC5B,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC;IAClC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,IAAI,MAAM,CAAC,KAAa;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,IAAI,aAAa;QACf,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,MAAmB;QACzB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC;QAClC,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC;QACzC,MAAM,iBAAiB,GAAG,sBAAsB,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QAEtE,mEAAmE;QACnE,IAAI,CAAC,MAAM,EAAE,CAAC;QAEd,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC;QAClB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAExC,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,iBAAiB,EAAE,CAAC;YACtB,sBAAsB,CAAC,eAAe,CACpC,IAAI,EACJ,iBAAiB,CAAC,QAAQ,IAAI,SAAS,EACvC,iBAAiB,CAAC,OAAO,IAAI,SAAS,CACvC,CAAC;QACJ,CAAC;QAED,2CAA2C;QAC3C,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CACV,OAAe,EACf,qBAA8B,EAC9B,oBAA6B;QAE7B,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC;IACnC,CAAC;IAED,uBAAuB,CAAC,OAAgB;QACtC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;gBACrD,IAAI,CAAC,wBAAwB,GAAG,KAAK,CAAC;gBACtC,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,OAAO;YACT,CAAC;YAED,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;YAC9B,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC9B,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;gBACrB,IAAI,CAAC,UAAU,GAAG,GAAG,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC7D,CAAC;YAED,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YAE7B,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAEvC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YAEjE,MAAM,UAAU,GAAG,GAAG,EAAE;gBACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACnB,OAAO;gBACT,CAAC;gBACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnB,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;oBAC7C,IAAI,CAAC,IAAI,CAAC,mBAAmB,EAAE;wBAC7B,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1C,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;qBAClC,CAAC,CAAC;gBACL,CAAC;gBACD,IAAI,CAAC,eAAe,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAC3D,CAAC,CAAC;YACF,IAAI,CAAC,eAAe,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAEzD,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;YAC5B,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;gBACjC,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAC3C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;YAC9B,CAAC;YAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;YACvB,CAAC;YAED,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;gBAC9B,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;gBAC7B,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YAC3C,CAAC;YAED,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,eAAe,CAAC,MAAc,EAAE,sBAA+C;QAC7E,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC;QACjC,IAAI,CAAC,kBAAkB,GAAG,sBAAsB,KAAK,MAAM,CAAC;QAC5D,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,IAAI,CAAC,kBAAkB,CAAC;QACpD,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,MAAM;QACJ,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,EAAE,CAAC;YACjC,oBAAoB,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC3C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;QAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;QAED,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC;YAC7B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;QAED,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,kBAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,sBAAsB,CACpB,MAAe,EACf,QAAwB,EACxB,OAAgC;QAEhC,IAAI,MAAM,EAAE,CAAC;YACX,sBAAsB,CAAC,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAClE,CAAC;aAAM,CAAC;YACN,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED,wBAAwB,CAAC,QAAuB;QAC9C,sBAAsB,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,uBAAuB;QACrB,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,cAAc;QACZ,IAAI,CAAC;YACH,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QACnE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;YACnC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACvC,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAEzC,6CAA6C;QAC7C,KAAK,CAAC,YAAY,GAAG,GAAG,EAAE;YACxB,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC;YAC9B,oCAAoC;YACpC,IAAI,GAAG,GAAG,YAAY,EAAE,CAAC;gBACvB,YAAY,GAAG,GAAG,CAAC;YACrB,CAAC;YACD,IAAI,GAAG,GAAG,YAAY,IAAI,WAAW,EAAE,CAAC;gBACtC,YAAY,GAAG,GAAG,CAAC;gBACnB,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBACtE,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACnD,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBAChC,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACrC,OAAO,EAAE,IAAI,CAAC,SAAS;aACxB,CAAC,CAAC;YACH,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACjD,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE;YACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBAChC,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACrC,OAAO,EAAE,IAAI,CAAC,SAAS;aACxB,CAAC,CAAC;YACH,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACjD,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,KAAK,CAAC,QAAQ,GAAG,GAAG,EAAE;YACpB,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YACtE,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE;YACnB,YAAY,GAAG,CAAC,CAAC;YACjB,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,KAAK,CAAC,YAAY,GAAG,GAAG,EAAE;YACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,YAAY,GAAG,KAAK,CAAC,WAAW,CAAC;YACjC,IAAI,CAAC,IAAI,CAAC,sBAAsB,EAAE;gBAChC,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;gBACrC,QAAQ,EAAE,IAAI,CAAC,MAAM;aACtB,CAAC,CAAC;YACH,sBAAsB,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AAED,SAAS,YAAY,CAAC,MAAmB;IACvC,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;AAED,MAAM,OAAO,gBACX,SAAQ,UAAU,CAAC,IAAI,CAAC,YAA6B;IAGrD,YAAY,OAAkC;QAC5C,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,aAAa,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,EAAE,GAAG,MAAM,EAAE,CAAC;IACd,WAAW,GAAG,CAAC,CAAC;IAChB,GAAG,GAAkB,IAAI,CAAC;IAElB,OAAO,CAA4B;IACnC,aAAa,GAAyB,IAAI,CAAC;IAC3C,oCAAoC,GAAG,CAAC,CAAC;IACzC,wBAAwB,GAAG,KAAK,CAAC;IACjC,UAAU,GAAa,EAAE,CAAC;IAC1B,YAAY,GAAqB,EAAE,CAAC;IACpC,gBAAgB,GAAkB,IAAI,CAAC;IACvC,MAAM,GAAuB,IAAI,CAAC;IAClC,kBAAkB,GAAwB,IAAI,CAAC;IAC/C,QAAQ,GAAwB,IAAI,CAAC;IACrC,cAAc,GAAqC,IAAI,CAAC;IACxD,cAAc,GAAsC,IAAI,CAAC;IACzD,eAAe,GAAG,KAAK,CAAC;IAEhC,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,aAAa,EAAE,KAAK,KAAK,WAAW,CAAC;IACnD,CAAC;IAED,MAAM,CAAC,OAA+B;QACpC,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,iJAAiJ,CAClJ,CAAC;QACJ,CAAC;QAED,8BAA8B;QAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,wFAAwF;QACxF,mDAAmD;QACnD,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;QAEtC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAE5B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,IAAI,CAAC,UAAU,CAAC,IAAI,CAClB,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC,CACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,oBAAoB;QAC1B,IAAI,IAAI,CAAC,aAAa,EAAE,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC3C,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,eAAe;QACb,MAAM,QAAQ,GACZ,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC;QACpF,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC;QAC1E,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CACpB,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI;YACtB,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,GAAG,EAAE,SAAS;SACf,CACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,oBAAoB;QACxB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,SAAS;QACP,MAAM,MAAM,GAAkB;YAC5B,SAAS,EACP,IAAI,CAAC,aAAa,EAAE,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,aAAa,EAAE,KAAK,KAAK,UAAU;YACvF,WAAW,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,KAAK,WAAW;YACtD,cAAc,EAAE,IAAI,CAAC,8BAA8B,EAAE;YACrD,qBAAqB,EAAE,KAAK;YAC5B,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC;QACF,IAAI,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC;YAC1D,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC5C,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,iJAAiJ,CAClJ,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;IAED,iBAAiB,CAAC,OAAe;QAC/B,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,QAAQ,CAAC,KAAa;QACpB,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,KAAK,KAAK,CAAC,EAAE,CAAC;YAC9D,MAAM,IAAI,KAAK,CAAC,wCAAwC,KAAK,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,oBAAoB,CAAC,OAAe;QAClC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,iJAAiJ,CAClJ,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAChD,IAAI,CAAC,aAAa,EAAE,gBAAgB,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAC9E,CAAC;QAEF,IAAI,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAE1B,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC;QAC/B,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAEtC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QAEf,IAAI,CAAC,IAAI,CAAC,uBAAuB,EAAE;YACjC,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,IAAI;YACX,GAAG;SACJ,CAAC,CAAC;IACL,CAAC;IAED,aAAa;QACX,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAC/B,OAAiE;QAEjE,IAAI,OAAO,SAAS,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,CAAC,oCAAoC,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;QAErB,MAAM,gBAAgB,GAAG,IAAI,CAAC,gBAAgB;YAC5C,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,gBAAgB,EAAE,EAAE;YAChD,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAC/D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEhC,IAAI,CAAC,kBAAkB,GAAG,GAAG,EAAE;YAC7B,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC5B,CAAC,CAAC;QACF,SAAS,CAAC,YAAY,CAAC,gBAAgB,CAAC,cAAc,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAEjF,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAC9B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;YAC9B,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC9B,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,CAAC;YACD,IAAI,CAAC,cAAc,GAAG,GAAG,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;YAC1D,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;YACrC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;YAC7B,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,CAAC,cAAc,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YACxE,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;QAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,YAAY,CAAC,GAAG,CAAC;QACnD,MAAM,oBAAoB,GAAyB,EAAE,CAAC;QAEtD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ,CAAC;QACvD,IAAI,QAAQ,IAAI,aAAa,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,oBAAoB,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC3C,CAAC;QAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,oBAAoB,CAAC,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;QAC7D,CAAC;aAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAC3B,oBAAoB,CAAC,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,oBAAoB,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;QAC9D,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;QAEtE,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAC3C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,8BAA8B,EAAE,CAAC;YACzD,IAAI,CAAC,wBAAwB,GAAG,KAAK,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,aAAa,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE;YAC5C,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvD,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,aAAa,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YAC3C,IAAI,CAAC,oCAAoC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvD,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;YACrB,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,aAAa,EAAE,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE;YAC3C,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;YACrB,IAAI,CAAC,wBAAwB,GAAG,KAAK,CAAC;YACtC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YAEnB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;gBACxB,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,CAAC;gBACjC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC;YACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;gBAC3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC7B,CAAC;YAED,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,SAAS,CAAC,YAAY,EAAE,mBAAmB,CAAC,cAAc,EAAE,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBACrF,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;YACjC,CAAC;YAED,sCAAsC;YACtC,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,OAAO,aAAa,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC9B,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;QAChE,IAAI,CAAC,YAAY,GAAG,OAAO;aACxB,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC;aAChD,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAChB,GAAG,EAAE,MAAM,CAAC,QAAQ;YACpB,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,gBAAgB;YACtC,IAAI,EAAE,MAAM,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;SAC5D,CAAC,CAAC,CAAC;IACR,CAAC;IAED,8EAA8E;IAC9E,iEAAiE;IACzD,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC;QACd,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC1D,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACpD,UAAU,IAAI,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAC/D,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC;QACd,CAAC;QACD,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IAEO,8BAA8B;QACpC,IAAI,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,IAAI,IAAI,CAAC,wBAAwB,IAAI,IAAI,CAAC,oCAAoC,GAAG,CAAC,EAAE,CAAC;YACnF,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,oCAAoC,CAAC;QACrE,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;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 { Asset } from 'expo-asset';\nimport { PermissionResponse, PermissionStatus } from 'expo-modules-core';\n\nimport {\n AudioMetadata,\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 { AudioLockScreenOptions } from './AudioConstants';\nimport {\n AUDIO_SAMPLE_UPDATE,\n PLAYBACK_STATUS_UPDATE,\n RECORDING_STATUS_UPDATE,\n} from './AudioEventKeys';\nimport { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types';\nimport { mediaSessionController } from './MediaSessionController.web';\nimport { RecordingPresets } from './RecordingConstants';\n\nconst nextId = (() => {\n let id = 0;\n return () => id++;\n})();\n\nlet audioContext: AudioContext | null = null;\n\nfunction getAudioContext(): AudioContext {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n return audioContext;\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 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\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 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\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/src/AudioModule.web.ts b/packages/expo-audio/src/AudioModule.web.ts index 5ba3529d6fe6bb..eb6538521ace0a 100644 --- a/packages/expo-audio/src/AudioModule.web.ts +++ b/packages/expo-audio/src/AudioModule.web.ts @@ -1,42 +1,10 @@ -import { Asset } from 'expo-asset'; import { PermissionResponse, PermissionStatus } from 'expo-modules-core'; -import { - AudioMetadata, - AudioMode, - AudioPlayerOptions, - AudioSource, - AudioStatus, - PitchCorrectionQuality, - RecorderState, - RecordingInput, - RecordingOptions, - RecordingOptionsWeb, - RecordingStartOptions, -} from './Audio.types'; -import { AudioLockScreenOptions } from './AudioConstants'; -import { - AUDIO_SAMPLE_UPDATE, - PLAYBACK_STATUS_UPDATE, - RECORDING_STATUS_UPDATE, -} from './AudioEventKeys'; -import { AudioPlayer, AudioEvents, RecordingEvents, AudioRecorder } from './AudioModule.types'; -import { mediaSessionController } from './MediaSessionController.web'; -import { RecordingPresets } from './RecordingConstants'; +import { AudioMode } from './Audio.types'; +import { getUserMedia } from './AudioUtils.web'; -const nextId = (() => { - let id = 0; - return () => id++; -})(); - -let audioContext: AudioContext | null = null; - -function getAudioContext(): AudioContext { - if (!audioContext) { - audioContext = new AudioContext(); - } - return audioContext; -} +export { AudioPlayerWeb } from './AudioPlayer.web'; +export { AudioRecorderWeb } from './AudioRecorder.web'; async function getPermissionWithQueryAsync( name: PermissionNameWithAdditionalValues @@ -59,711 +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'; - 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; - } -} - -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[] = []; - 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; - } -} - 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; +} From 2277cfe9387cb0236102798f0e7758cfaaf89b21 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Mon, 16 Feb 2026 13:32:48 +0000 Subject: [PATCH 11/16] feat(expo-server): Add module preloading method to EAS/workerd adapters (#43171) # Why This allows us to preload all server modules in one method. This is useful to hoist loading of any split modules to an ahead of time point (e.g. top-level await) # How - Add `preload` common environment method - Expose `preload` method on EAS and workerd request handler # Test Plan - Ran through a manual deployment flow, works as expected # Checklist - [x] I added a `changelog.md` entry and rebuilt the package sources according to [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md) --- packages/expo-server/CHANGELOG.md | 2 + .../expo-server/build/cjs/vendor/eas.d.ts | 5 +- packages/expo-server/build/cjs/vendor/eas.js | 12 ++- .../expo-server/build/cjs/vendor/eas.js.map | 2 +- .../build/cjs/vendor/environment/common.d.ts | 8 +- .../build/cjs/vendor/environment/common.js | 52 ++++++---- .../cjs/vendor/environment/common.js.map | 2 +- .../build/cjs/vendor/environment/node.d.ts | 9 +- .../build/cjs/vendor/environment/node.js.map | 2 +- .../build/cjs/vendor/environment/workerd.d.ts | 9 +- .../cjs/vendor/environment/workerd.js.map | 2 +- .../expo-server/build/cjs/vendor/workerd.d.ts | 5 +- .../expo-server/build/cjs/vendor/workerd.js | 12 ++- .../build/cjs/vendor/workerd.js.map | 2 +- .../expo-server/build/mjs/vendor/eas.d.ts | 5 +- packages/expo-server/build/mjs/vendor/eas.js | 12 ++- .../expo-server/build/mjs/vendor/eas.js.map | 2 +- .../build/mjs/vendor/environment/common.d.ts | 8 +- .../build/mjs/vendor/environment/common.js | 52 ++++++---- .../mjs/vendor/environment/common.js.map | 2 +- .../build/mjs/vendor/environment/node.d.ts | 9 +- .../build/mjs/vendor/environment/node.js.map | 2 +- .../build/mjs/vendor/environment/workerd.d.ts | 9 +- .../mjs/vendor/environment/workerd.js.map | 2 +- .../expo-server/build/mjs/vendor/workerd.d.ts | 5 +- .../expo-server/build/mjs/vendor/workerd.js | 12 ++- .../build/mjs/vendor/workerd.js.map | 2 +- packages/expo-server/src/vendor/eas.ts | 23 +++-- .../src/vendor/environment/common.ts | 97 ++++++++++++------- .../src/vendor/environment/node.ts | 4 +- .../src/vendor/environment/workerd.ts | 4 +- packages/expo-server/src/vendor/workerd.ts | 23 +++-- 32 files changed, 237 insertions(+), 160 deletions(-) diff --git a/packages/expo-server/CHANGELOG.md b/packages/expo-server/CHANGELOG.md index 7e3d192cc309ef..885ee39c12c839 100644 --- a/packages/expo-server/CHANGELOG.md +++ b/packages/expo-server/CHANGELOG.md @@ -14,6 +14,8 @@ ### 💡 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/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 82849b74e499a1..fad652747828dc 100644 --- a/packages/expo-server/build/cjs/vendor/eas.js +++ b/packages/expo-server/build/cjs/vendor/eas.js @@ -19,10 +19,12 @@ function createRequestHandler(params, setup) { 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 9c21559a08d02a..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,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,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.map b/packages/expo-server/build/cjs/vendor/environment/node.js.map index 90c8a81d940f4a..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;AAWD,wDAMC;AApED,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,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 +{"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.map b/packages/expo-server/build/cjs/vendor/environment/workerd.js.map index 9d235ff9becace..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/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/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 e4abacbe8940e1..c155983726857d 100644 --- a/packages/expo-server/build/mjs/vendor/eas.js +++ b/packages/expo-server/build/mjs/vendor/eas.js @@ -14,10 +14,12 @@ export function createRequestHandler(params, setup) { 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 6dfe471238843b..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,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,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":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAG1D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAExF,SAAS,kBAAkB,CAAC,QAAqB;IAC/C,OAAO;QACL,GAAG,QAAQ;QACX,UAAU,EACR,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACnC,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;SACzC,CAAC,CAAC,IAAI,EAAE;QACX,SAAS,EACP,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClC,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;SACzC,CAAC,CAAC,IAAI,EAAE;QACX,cAAc,EACZ,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACvC,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;SACzC,CAAC,CAAC,IAAI,EAAE;QACX,SAAS,EACP,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAClC,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;SACzC,CAAC,CAAC,IAAI,EAAE;QACX,QAAQ,EACN,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YACjC,GAAG,KAAK;YACR,UAAU,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;SACzC,CAAC,CAAC,IAAI,EAAE;KACZ,CAAC;AACJ,CAAC;AAkBD,MAAM,UAAU,iBAAiB,CAAC,KAAuB;IACvD,iEAAiE;IACjE,IAAI,cAA2C,CAAC;IAChD,IAAI,WAAW,GAAuB,IAAI,CAAC;IAE3C,KAAK,UAAU,iBAAiB;QAC9B,IAAI,cAAc,KAAK,SAAS,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;YACxD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,mBAAmB,CAAC,CAAC;YACvD,cAAc,GAAG,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAmB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzE,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED,KAAK,UAAU,iBAAiB;QAC9B,IAAI,WAAW,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YACxC,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;QAC3C,IAAI,QAAQ,EAAE,SAAS,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC;QACd,CAAC;QAED,0FAA0F;QAC1F,YAAY;QACZ,MAAM,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,UAAU,CACvC,QAAQ,CAAC,SAAS,CAAC,IAAI,CACxB,CAA8B,CAAC;QAEhC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,WAAW,GAAG,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACvC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;YAChE,OAAO,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE;gBAC1C,MAAM,EAAE,OAAO,EAAE,MAAM;gBACvB,OAAO;gBACP,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC;QACF,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,KAAK,UAAU,aAAa,CAC1B,OAAgB,EAChB,KAAY,EACZ,MAA8B;QAE9B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,CAAwB,CAAC;QACnF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,+BAA+B,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,CAAC;QAED,OAAO,YAAY,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IACpE,CAAC;IAED,OAAO;QACL,iBAAiB;QAEjB,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK;YAC1B,yDAAyD;YACzD,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;YAC3C,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,aAAwC,CAAC;gBAE7C,IAAI,CAAC;oBACH,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;wBACjB,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;wBAC3C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;wBAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;wBAC/D,aAAa,GAAG;4BACd,MAAM,EAAE;gCACN,IAAI,EAAE,IAAI,IAAI,IAAI;gCAClB,GAAG,EAAE,uBAAuB,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;6BACjD;yBACF,CAAC;oBACJ,CAAC;oBACD,OAAO,MAAM,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;gBAChD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;oBAC1C,MAAM,KAAK,CAAC;gBACd,CAAC;YACH,CAAC;YAED,iDAAiD;YACjD,IAAI,IAAmB,CAAC;YACxB,IAAI,CAAC,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;gBAChE,OAAO,IAAI,CAAC;YACd,CAAC;YACD,uDAAuD;YACvD,+CAA+C;YAC/C,MAAM,UAAU,GAAG,QAAQ,CAAC;YAC5B,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;gBAC7E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACrD,IAAI,CAAC,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;oBAC1D,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,KAAK;YACrB,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,UAAU;YAC5B,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAQ,CAAC;YAC7D,IAAI,OAAO,GAAG,EAAE,OAAO,KAAK,UAAU,EAAE,CAAC;gBACvC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK;YAChC,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;YAE3D,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvB,OAAO,MAAM,CAAC;YAChB,CAAC;YAED,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,OAAO;YACX,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;gBACxB,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,iBAAiB,EAAE,CAAC;YAC3C,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,QAAQ,GAAa,EAAE,CAAC;gBAC9B,IAAI,QAAQ,CAAC,UAAU;oBAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBACjE,IAAI,QAAQ,CAAC,SAAS;oBAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;gBAC/D,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS;oBAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACxE,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;oBAC5C,IAAI,SAAS,CAAC,MAAM;wBAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBACxD,CAAC;gBACD,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"} \ 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.map b/packages/expo-server/build/mjs/vendor/environment/node.js.map index 7fe31d941b59d4..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,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 +{"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.map b/packages/expo-server/build/mjs/vendor/environment/workerd.js.map index 8be67d410f9ee5..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":"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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/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/vendor/eas.ts b/packages/expo-server/src/vendor/eas.ts index 2c277df14f17fc..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(); @@ -27,9 +26,13 @@ export function createRequestHandler( 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 1a98c1819fbddd..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) { diff --git a/packages/expo-server/src/vendor/environment/workerd.ts b/packages/expo-server/src/vendor/environment/workerd.ts index 22029f9bbbd05b..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(); 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; } From d3e4198a554a145d33dc54427a923109a08d124f Mon Sep 17 00:00:00 2001 From: Patryk Mleczek <67064618+pmleczek@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:36:48 +0100 Subject: [PATCH 12/16] [github][brownfield] split android e2e into two jobs (#43164) # Why The tests in the previous setup: - Brownfield artifacts publishing - Test app build - Maestro execution on emulator All executed in a single job were unstable, ending in: ```sh FATAL | Not enough space to create userdata partition. Available: 4031.36 MB \ at /home/runner/.android/avd/avd-36.avd, need 7372.80 MB. ``` # How Split the publishing & building app and test execution into two jobs, similar to other E2E workflows # Test Plan Ensured the updated setup works on CI # Checklist N / A --- .../test-suite-brownfield-isolated.yml | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) 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 From 098886751a456fd27d72c3d3e37abde824e0f027 Mon Sep 17 00:00:00 2001 From: Jakub Grzywacz Date: Mon, 16 Feb 2026 15:07:34 +0100 Subject: [PATCH 13/16] [widgets] Create widgets runtime bundle at build time (#43170) # Why * Maintaining `expo-ui.bundle.swift` is almost impossible to be up-to-date * User can have different expo-ui version # How Use scripts similar to `@expo/log-box` to add a build step that prepares the bundle. # Test Plan Run widgets-tester. Everything should still work without any changes. --- packages/expo-widgets/CHANGELOG.md | 1 + packages/expo-widgets/app.json | 14 ++++ packages/expo-widgets/bundle/.gitignore | 1 + .../expo-widgets/bundle/expo-module-stub.ts | 15 ++++ packages/expo-widgets/bundle/index.ts | 70 +++++++++++++++++++ .../expo-widgets/bundle/jsx-runtime-stub.ts | 57 +++++++++++++++ packages/expo-widgets/bundle/react-stub.ts | 11 +++ packages/expo-widgets/ios/ExpoWidgets.podspec | 34 +++++++++ .../ios/Widgets/WidgetContext.swift | 10 ++- .../ios/Widgets/expo-ui.bundle.swift | 69 ------------------ packages/expo-widgets/metro.config.js | 56 +++++++++++++++ packages/expo-widgets/package.json | 1 + .../expo-widgets/scripts/build-bundle.mjs | 48 +++++++++++++ packages/expo-widgets/scripts/with-node.sh | 44 ++++++++++++ 14 files changed, 360 insertions(+), 71 deletions(-) create mode 100644 packages/expo-widgets/app.json create mode 100644 packages/expo-widgets/bundle/.gitignore create mode 100644 packages/expo-widgets/bundle/expo-module-stub.ts create mode 100644 packages/expo-widgets/bundle/index.ts create mode 100644 packages/expo-widgets/bundle/jsx-runtime-stub.ts create mode 100644 packages/expo-widgets/bundle/react-stub.ts delete mode 100644 packages/expo-widgets/ios/Widgets/expo-ui.bundle.swift create mode 100644 packages/expo-widgets/metro.config.js create mode 100755 packages/expo-widgets/scripts/build-bundle.mjs create mode 100755 packages/expo-widgets/scripts/with-node.sh 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 From af26e2f568c190f107ab6fdfdd764fc9cd517a76 Mon Sep 17 00:00:00 2001 From: Ray <153027766+ramonclaudio@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:08:18 -0500 Subject: [PATCH 14/16] [ios][ui] Fix clipShape and mask modifiers ignoring capsule and ellipse shapes (#43158) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem `ClipShapeModifier` and `MaskModifier` use a raw `String` for the shape field instead of the `ShapeType` enum. Only `"circle"` and `"roundedRectangle"` are handled -- everything else falls through to `Rectangle()` silently. So `clipShape("capsule")` renders a rectangle. No error, no warning. Every other shape modifier (`BackgroundModifier`, `ContainerShapeModifier`, `ContentShapeModifier`, `GlassEffectModifier`) uses `ShapeType` with exhaustive switching. These two just got missed when `ShapeType` was introduced in #40748. ## Fix - `ClipShapeModifier`: `@Field var shape: String` → `@Field var shape: ShapeType` - `MaskModifier`: `@Field var shape: String` → `@Field var shape: ShapeType` - Exhaustive switch on all 5 `ShapeType` cases, no `default` fallthrough - Added `roundedCornerStyle` and `cornerSize` fields, switched to `makeCapsule(style:)` and `makeRoundedRectangle(cornerRadius:cornerSize:style:)` helpers to match `ContentShapeModifier`/`BackgroundModifier`/`ContainerShapeModifier` - TypeScript types for `clipShape()` and `mask()` updated to include `'capsule' | 'ellipse'` ## Test plan - `clipShape("capsule")` → capsule clipping (not rectangle) - `clipShape("ellipse")` → ellipse clipping (not rectangle) - `mask("capsule")` / `mask("ellipse")` → same - Existing shapes (`rectangle`, `circle`, `roundedRectangle`) unchanged --- packages/expo-ui/CHANGELOG.md | 1 + .../build/swift-ui/modifiers/index.d.ts | 4 +-- .../build/swift-ui/modifiers/index.d.ts.map | 2 +- .../ios/Modifiers/ViewModifierRegistry.swift | 32 +++++++++++++------ .../expo-ui/src/swift-ui/modifiers/index.ts | 8 +++-- 5 files changed, 31 insertions(+), 16 deletions(-) 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. From 06b8bfe6ee553380da306a3afbea3ad254213309 Mon Sep 17 00:00:00 2001 From: Patryk Mleczek <67064618+pmleczek@users.noreply.github.com> Date: Mon, 16 Feb 2026 15:21:06 +0100 Subject: [PATCH 15/16] [github][brownfield] optimize runner usage for ios compilation test (#43169) # Why There were some insights from the team, that compilation test for iOS is clogging the CI, as it occupies two runners for around an hour # How iOS compilation test now runs as a single job, thus occupying only one runner for roughly two hours # Test Plan Ensured that the updated workflow passes on the CI # Checklist N / A --- .github/workflows/brownfield.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) 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 From 60589868221605cf363cf7efede489d5e124ef28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kosmaty?= Date: Mon, 16 Feb 2026 16:09:14 +0100 Subject: [PATCH 16/16] [core][Android] Remove `ReactNativeFeatureFlags.enableBridgelessArchitecture` (#42906) --- .../ReactNativeFeatureFlags.kt | 12 ----- .../modules/ReactActivityDelegateWrapper.kt | 44 +++---------------- 2 files changed, 7 insertions(+), 49 deletions(-) delete mode 100644 packages/expo-modules-core/android/src/main/java/expo/modules/rncompatibility/ReactNativeFeatureFlags.kt 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/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) } }