From adf27de7d036fff1d81a454c7539789cf835c66e Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 20 Oct 2026 11:59:49 +0700 Subject: [PATCH] Keep Explorer consistent across phone, tablet and desktop layouts (#7424) * Upgrade to Expo 57 and unify Explorer across layouts * feat(app): retain Explorer across layout and appearance changes Keep one workspace Explorer host and destination-aware navigation so folding, theme updates and compact sheets preserve the current panel. Scope pull request discovery and timeline demand to active surfaces. * fix(app): keep Explorer resize handles stretched through the dock The shared frame moved the divider into an absolute column, leaving its horizontal handle without height. Restore the row so pointer drags reach it, preserving the existing resize and performance contract. * fix(app): keep Explorer drag widths out of the shared stylesheet Carry the existing inline sizing policy into the shared frame so pointer previews do not accumulate CSS rules. * fix(test): align isolated test runtimes with Expo 57 Hoisted React consumers need the matching DOM renderer at the repository root. Automated Metro processes must not install native DevTools into disposable homes, and development toast overlays must not cover compact actions. Keep Explorer journeys on the shared host and synchronize setup fixtures on daemon output rather than a one-second file-marker window. A delayed real child start reproduces the readiness failure on every platform. * fix(test): await retained shell layout after composer resize The gesture host now stays mounted across breakpoints, so its presence no longer identifies compact layout. Report the current layout on the retained host and synchronize composer journeys with that state. * fix(app): preserve browser interactions in retained workspace hosts Initially disabled gesture hosts still registered pointer and wheel listeners, while hover cards used window positions inside a workspace-local sheet portal. Respect initial gesture enablement and position cards relative to their measured floating host. Keep developer-toast dismissal independent of pointer input and replacement toast visibility so modal, hover, and focus checks retain their input state. * fix(test): share developer toast handling with Electron browser runs The standalone Electron browser runner bypassed the browser fixture, allowing developer errors to cover Settings. Use the same non-pointer dismissal in both runners while retaining their console logs. --- docs/explorer-sidebar.md | 58 +- docs/expo-router.md | 4 +- docs/mobile-panels.md | 4 +- docs/testing.md | 2 +- package-lock.json | 10089 ++++++++++------ package.json | 13 +- packages/app/app.config.js | 1 + .../browser/add-changed-file-to-chat.spec.ts | 80 +- packages/app/e2e/browser/changes-pane.spec.ts | 31 +- .../browser/compact-git-actions-menu.spec.ts | 4 +- .../e2e/browser/composer-diff-stat.spec.ts | 9 +- .../app/e2e/browser/explorer-sidebar.spec.ts | 292 +- .../new-workspace-launch-terminal.spec.ts | 4 +- .../app/e2e/browser/plugin-host-ui.spec.ts | 11 - .../app/e2e/browser/plugin-modal-body.spec.ts | 8 +- .../sidebar-mobile-menu-sheets.spec.ts | 3 + .../app/e2e/browser/sidebar-workspace.spec.ts | 6 +- packages/app/e2e/browser/usage-modal.spec.ts | 5 +- .../agent-device/file-context-menu.ios.ad | 4 +- packages/app/e2e/support/developer-ui.mjs | 10 + packages/app/e2e/support/fixtures.ts | 3 + packages/app/e2e/support/global-setup.ts | 2 + packages/app/e2e/support/helpers/composer.ts | 9 +- .../app/e2e/support/helpers/context-window.ts | 2 +- packages/app/e2e/support/helpers/sidebar.ts | 13 +- packages/app/package.json | 77 +- packages/app/plugins/with-paste-input.js | 64 +- packages/app/plugins/with-paste-input.test.ts | 30 +- packages/app/src/agent-skills/index.tsx | 2 +- packages/app/src/agent-stream/view.tsx | 5 - packages/app/src/app/_layout.tsx | 72 +- packages/app/src/app/h/[serverId]/_layout.tsx | 7 +- .../workspace/[workspaceId]/index.tsx | 2 +- packages/app/src/app/pair-scan.tsx | 2 +- .../app/src/command-center/command-center.tsx | 2 +- .../src/components/adaptive-modal-sheet.tsx | 4 +- .../app/src/components/add-project-flow.tsx | 2 +- .../appearance-style-boundary.test.ts | 95 +- ...ompact-explorer-sidebar-host-state.test.ts | 106 - .../compact-explorer-sidebar-host-state.ts | 59 - .../compact-explorer-sidebar-host.tsx | 216 - .../components/compact-explorer-sidebar.tsx | 574 - .../components/desktop-sidebar-layout.test.ts | 22 + .../src/components/desktop-sidebar-layout.ts | 9 +- .../explorer-sidebar-layout.test.ts | 22 +- .../src/components/explorer-sidebar-layout.ts | 29 +- .../file-drop/file-drop-backdrop.tsx | 4 +- .../src/components/headers/compact-header.tsx | 11 +- packages/app/src/components/left-sidebar.tsx | 4 +- .../src/components/sidebar-workspace-list.tsx | 2 +- .../app/src/components/split-container.tsx | 721 +- .../app/src/components/split-drop-zone.tsx | 2 +- packages/app/src/components/terminal-pane.tsx | 2 +- packages/app/src/components/ui/combobox.tsx | 2 +- .../components/ui/floating-panel-portal.tsx | 2 +- packages/app/src/components/ui/hover-card.tsx | 28 +- .../host-scope.tsx | 2 +- .../src/components/ui/menu/menu-overlay.tsx | 2 +- .../components/ui/press-highlight.native.tsx | 4 +- packages/app/src/components/ui/shortcut.tsx | 2 +- .../components/workspace-tab-drag-context.ts | 12 + .../components/workspace-tab-drag-policy.ts | 9 + .../components/workspace-tab-drag-scope.tsx | 5 + .../workspace-tab-drag-scope.web.tsx | 494 + .../app/src/composer/draft/workspace-tab.tsx | 3 +- packages/app/src/constants/layout.ts | 2 +- .../components/integrations-section.tsx | 2 +- packages/app/src/file-pane/pane.tsx | 71 +- packages/app/src/git/diff-pane.tsx | 3 +- .../app/src/git/pull-request-connection.tsx | 27 + .../git/pull-request-panel/use-data.test.ts | 4 +- .../src/git/pull-request-panel/use-data.ts | 11 +- packages/app/src/git/use-pr-status-query.ts | 8 +- packages/app/src/hosts/host-chooser.tsx | 2 +- packages/app/src/keyboard/shift/index.ts | 1 - .../keyboard/shift/internal/policy.test.ts | 15 - .../app/src/keyboard/shift/internal/policy.ts | 7 - .../mobile-panels/explorer-open-gesture.tsx | 60 + packages/app/src/mobile-panels/gestures.ts | 26 +- .../app/src/mobile-panels/presentation.tsx | 51 +- packages/app/src/mobile-panels/provider.tsx | 3 - packages/app/src/navigation/themed-stack.tsx | 27 +- .../workspace-route-navigation.test.ts | 2 +- .../navigation/workspace-route-navigation.ts | 2 +- packages/app/src/panels/agent-panel.tsx | 4 +- packages/app/src/panels/agent-tracks.tsx | 5 +- .../src/panels/changes/presentation.test.ts | 22 + .../app/src/panels/changes/presentation.ts | 9 + packages/app/src/panels/diff-panel.tsx | 19 +- .../app/src/panels/pull-request-panel.tsx | 42 +- .../activity.integration.test.tsx | 249 + .../src/panels/pull-request/activity.test.ts | 51 + .../app/src/panels/pull-request/activity.ts | 12 + packages/app/src/panels/pull-request/data.ts | 11 + .../src/panels/pull-request/descriptor.tsx | 40 + .../app/src/panels/pull-request/discovery.ts | 65 + .../app/src/panels/pull-request/index.tsx | 56 +- .../retained-chat-content.browser.test.tsx | 101 + .../panels/retained-chat-content.native.tsx | 11 + .../app/src/panels/retained-chat-content.tsx | 12 +- packages/app/src/panels/terminal-panel.tsx | 15 +- .../app/src/panels/use-add-file-to-chat.ts | 6 +- .../src/screens/project-settings-screen.tsx | 2 +- packages/app/src/screens/schedules-screen.tsx | 2 +- packages/app/src/screens/sessions-screen.tsx | 2 +- packages/app/src/screens/settings-screen.tsx | 2 +- .../settings/keyboard-shortcuts-section.tsx | 2 +- .../screens/workspace/explorer-sidebar.tsx | 9 +- .../workspace/explorer-sidebar/frame-props.ts | 10 + .../workspace/explorer-sidebar/frame.tsx | 68 + .../explorer-sidebar/geometry-types.ts | 15 + .../workspace/explorer-sidebar/geometry.tsx | 86 + .../explorer-sidebar/geometry.web.tsx | 58 + .../app/src/screens/workspace/sheet-tabs.tsx | 2 +- .../workspace/visible-agent-ids.test.ts | 33 + .../screens/workspace/visible-agent-ids.ts | 10 +- .../workspace/workspace-desktop-tabs-row.tsx | 1 - .../workspace/workspace-explorer-toggle.tsx | 2 +- .../screens/workspace/workspace-screen.tsx | 272 +- .../workspace/workspace-tab-layout.test.ts | 26 + .../src/stores/explorer-checkout-context.ts | 5 - .../app/src/stores/explorer-tab-memory.ts | 34 - packages/app/src/stores/panel-store/index.ts | 59 +- .../app/src/stores/panel-store/state.test.ts | 139 +- packages/app/src/stores/panel-store/state.ts | 77 +- .../src/stores/workspace-layout-store.test.ts | 15 + .../app/src/stores/workspace-layout-store.ts | 74 +- packages/app/src/styles/unistyles.ts | 2 + packages/app/src/usage/window-bar.tsx | 4 +- .../workspace-tabs/explorer-sidebar.test.ts | 29 +- .../src/workspace-tabs/explorer-sidebar.ts | 73 +- .../app/src/workspace-tabs/launcher/index.tsx | 4 +- .../app/src/workspace-tabs/navigation.test.ts | 87 + packages/app/src/workspace-tabs/navigation.ts | 19 + .../app/src/workspace-tabs/open-beside.ts | 57 +- .../open-supporting-view.test.ts | 28 +- .../workspace-tabs/open-supporting-view.ts | 40 +- packages/app/vitest.config.ts | 2 + packages/desktop/e2e/browser-tabs.e2e.mjs | 3 + .../daemon-lifecycle-renderer.electron.mjs | 1 + .../ios/ExpoTwoWayAudioModule.swift | 4 +- .../ios/MicrophonePermissionRequester.swift | 6 +- packages/plugin/package.json | 6 +- ...rkspace-create-worktree-source.e2e.test.ts | 31 +- ...react-native-gesture-handler+2.32.0.patch} | 63 +- ...3.patch => react-native-svg+15.15.4.patch} | 0 scripts/postinstall-patches.mjs | 3 +- 147 files changed, 9652 insertions(+), 6248 deletions(-) create mode 100644 packages/app/e2e/support/developer-ui.mjs delete mode 100644 packages/app/src/components/compact-explorer-sidebar-host-state.test.ts delete mode 100644 packages/app/src/components/compact-explorer-sidebar-host-state.ts delete mode 100644 packages/app/src/components/compact-explorer-sidebar-host.tsx delete mode 100644 packages/app/src/components/compact-explorer-sidebar.tsx create mode 100644 packages/app/src/components/workspace-tab-drag-context.ts create mode 100644 packages/app/src/components/workspace-tab-drag-policy.ts create mode 100644 packages/app/src/components/workspace-tab-drag-scope.tsx create mode 100644 packages/app/src/components/workspace-tab-drag-scope.web.tsx create mode 100644 packages/app/src/git/pull-request-connection.tsx create mode 100644 packages/app/src/mobile-panels/explorer-open-gesture.tsx create mode 100644 packages/app/src/panels/changes/presentation.test.ts create mode 100644 packages/app/src/panels/changes/presentation.ts create mode 100644 packages/app/src/panels/pull-request/activity.integration.test.tsx create mode 100644 packages/app/src/panels/pull-request/activity.test.ts create mode 100644 packages/app/src/panels/pull-request/activity.ts create mode 100644 packages/app/src/panels/pull-request/data.ts create mode 100644 packages/app/src/panels/pull-request/descriptor.tsx create mode 100644 packages/app/src/panels/pull-request/discovery.ts create mode 100644 packages/app/src/panels/retained-chat-content.browser.test.tsx create mode 100644 packages/app/src/panels/retained-chat-content.native.tsx create mode 100644 packages/app/src/screens/workspace/explorer-sidebar/frame-props.ts create mode 100644 packages/app/src/screens/workspace/explorer-sidebar/frame.tsx create mode 100644 packages/app/src/screens/workspace/explorer-sidebar/geometry-types.ts create mode 100644 packages/app/src/screens/workspace/explorer-sidebar/geometry.tsx create mode 100644 packages/app/src/screens/workspace/explorer-sidebar/geometry.web.tsx delete mode 100644 packages/app/src/stores/explorer-checkout-context.ts delete mode 100644 packages/app/src/stores/explorer-tab-memory.ts create mode 100644 packages/app/src/workspace-tabs/navigation.test.ts create mode 100644 packages/app/src/workspace-tabs/navigation.ts rename patches/{react-native-gesture-handler+2.28.0.patch => react-native-gesture-handler+2.32.0.patch} (79%) rename patches/{react-native-svg+15.15.3.patch => react-native-svg+15.15.4.patch} (100%) diff --git a/docs/explorer-sidebar.md b/docs/explorer-sidebar.md index c9a89f8a58..9fe6bdfd7b 100644 --- a/docs/explorer-sidebar.md +++ b/docs/explorer-sidebar.md @@ -11,7 +11,7 @@ contracts. ## Panel host contract -Every desktop panel registers its supported `PaneHost` values and presentation. Launchers derive +Every panel registers its supported `PaneHost` values and presentation. Launchers derive fixed-target labels and icons from that registration, filter by host, and never substitute one panel type for another. Tab moves reject unsupported destinations, and placement resolves only to a compatible pane. @@ -21,7 +21,10 @@ so a pane’s + menu omits each while that pane already contains it. Closing one item available again. Other compatible tabs, including agents, terminals, files, and diffs, can move between Explorer and main panes. Keep panel implementations independent of either shell. `WorkspacePanelHost` owns mounting and -retention, while each shell owns its tabs, focus, dragging, resizing, and shortcuts. +retention. The shared Explorer owns its tab rail; its shared frame owns visibility, activity and +close-gesture lifetime. Platform adapters own resizing and inset geometry. +The host keeps three recently used tabs plus modified tabs; unmodified tabs beyond that budget +can remount. Native retained content stays live, while web chat uses its existing deferred Freeze. ## Sheets @@ -40,11 +43,11 @@ remounts its panel. Revealing a target that already has a sheet uncovers that sh ones above it, except ones holding unsaved work, which stay where they are. Opening a sheet as a tab dismisses the sheets above it, since the tab would sit under them. The stack is not persisted. -Sheets are modal and cover the whole compact column, header included. A sheet's header is its drag +Sheets are modal and cover the whole compact workspace, including the header and Explorer. A sheet's header is its drag handle, because the panel scrolls on its own and content panning would fight it. Its trailing rail holds icon buttons only (`SheetHeaderIconButton`): Open as tab is the full-screen glyph beside Close, so the title keeps its width. The sheets present -from inside the compact column's `SheetHostScope`, so their panels read the navigator and every +from the shared workspace's `SheetHostScope`, so their panels read the navigator and every workspace provider an ordinary pane has without a context bridge ([floating-panels.md Gotcha 6](floating-panels.md#gotcha-6--bottom-sheet-refs-are-not-lifecycle-truth)). @@ -56,12 +59,16 @@ the sheet's tab into a pane, and edits the autosave has not started writing are ## Explorer sidebar `packages/app/src/workspace-tabs/explorer-sidebar.ts` owns show, hide, toggle, and view selection. -On desktop, the shell is rendered outside the workspace split canvas so it divides the full -workspace, including the header. It has its own persisted width and resize handle. Main-pane splits +One Explorer host stays beside the center column across compact overlays and docks. Keep its +providers and gesture roots at the same React position when width or appearance changes. The +workspace route preserves panel ancestry during appearance updates. Appearance-dependent leaves +subscribe to theme changes; the file editor reconfigures its existing editor theme compartment. +Ordinary leaf routes retain the stack appearance policy. +The shell is outside the workspace split canvas so it divides the full workspace, including the header. It has its own persisted width and resize handle. Main-pane splits never read or modify that width. `packages/app/src/workspace-tabs/open-supporting-view.ts` owns semantic Changes and pull-request -opens. Compact and wide native layouts select the matching Explorer tab. Desktop Changes opens +opens. Compact and wide native layouts select the matching workspace tab in Explorer. Desktop Changes opens follow the shared diff preference. Desktop pull requests use their Main panel, On the side, or Explorer sidebar setting. Automatic PR discovery follows that preference once per workspace without interrupting the user's work. Closing the tab opts that workspace out of future automatic opens, @@ -76,18 +83,37 @@ literal `"explorer"` pane id and `explorerPaneIdByWorkspace` key for compatibili Explorer uses the shared workspace tab row and ordinary tab context menus. Files and Changes hide their close buttons through the panel manifest; close them from the tab context menu. -Other tabs reveal the close control on hover. The + menu opens compatible panels in the dock and -omits Agent and terminal profiles. Agents and terminals can still be dragged into Explorer. +Other tabs reveal the close control on hover. The + menu opens compatible panels in the dock, including Agent and terminal profiles. +Web also supports dragging agents and terminals into Explorer. Bulk-close actions apply only to the dock's tabs. Explorer tabs can be reordered and dragged between compatible panes, but the dock cannot be split or maximized. Selecting an Explorer tab -does not change workspace focus. +does not change workspace focus. Web dragging shares the workspace drag scope; compact layouts +accept only reordering inside the source pane. -Cmd+E shows or hides Explorer without changing its selected view. Compact layouts use the combined -full-screen Explorer overlay for Changes, Files, and pull requests, and close it after a file opens. Compact Changes has no tree rail; its overview is the Jump to file action (`packages/app/src/git/jump-to-file/`), a sheet over the same changed-files tree the desktop rail renders. -Wide native layouts without pane splits use the same combined content in a resizable inline dock; -opening a file leaves that dock visible. Both presentations keep their selection in the panel store -and reuse the layout store's per-workspace Explorer width. They do not create a second Explorer -lifecycle. +Cmd+E shows or hides Explorer without changing its selected view. All layouts use the same +workspace tabs, launcher, and panel host. Below 600 points the shell is the swipeable Explorer +overlay; at 600 points and above it reserves width beside the workspace. Native docking keeps its +touch resize handle. Full workspace splits remain a separate web-only capability. + +The dock reserves at least 240 points and the workspace 360. App navigation yields when it cannot +share the remaining width with both. This keeps a portrait tablet from rendering three unusably +narrow columns; widening restores navigation without changing its saved open state. + +Compact panel gestures own overlay visibility; the workspace layout owns its tab selection and +contents on every platform. Explicit pane destinations bypass compact sheet placement, so choosing +a panel in Explorer's + menu keeps it there. Ordinary compact file and subagent look-ups still use +the sheet policy. Resolving an existing main tab reveals center immediately; a new file sheet +keeps Explorer underneath and closing the sheet uncovers it. Semantic navigation resolves the +actual destination before revealing it, including deduplicated targets. + +Compact overlay selection and saved dock visibility are independent. Folding changes geometry, +not either mode’s visibility intent. Native workspace retention remains one workspace; web retains +up to ten with its existing inactive TTL. + +PR discovery belongs to the active workspace: split layouts discover while active, and other +layouts discover while Explorer is active. The rail requests summary status; selected visible PR +content also requests timeline data. Inactive consumers read cached data without request demand. +Discovery uses ordinary PR tabs and their existing once-per-workspace close opt-out. ## Side pane diff --git a/docs/expo-router.md b/docs/expo-router.md index 6ff9d14c9c..cc65eb57a7 100644 --- a/docs/expo-router.md +++ b/docs/expo-router.md @@ -157,7 +157,9 @@ a small `withUnistyles` boundary without subscribing the route tree itself to every Unistyles runtime update. Navigators keep their identity across appearance changes. `ThemedStack` remounts -each screen's content below the native stack when appearance tokens change; a +each ordinary screen's content below the native stack when appearance tokens change. +Workspace screens own retained panel lifetimes and update appearance at their +leaves through `screenOwnedAppearance` ([Explorer](explorer-sidebar.md)). A keyed wrapper above a stack remounts the stack itself, and Android crashes when that happens while a FragmentManager transaction is running, which settings hydration at startup makes likely. A screen that mounts a nested navigator (the diff --git a/docs/mobile-panels.md b/docs/mobile-panels.md index 6bd528e3e8..3301b4b60a 100644 --- a/docs/mobile-panels.md +++ b/docs/mobile-panels.md @@ -32,7 +32,9 @@ The UI worklet owns transient motion: React publishes the active panel only when the canonical target and the UI-thread position agree at the final anchor. Retained content never observes gesture previews, progress, or an unsettled target. -The gesture hosts stay mounted. Native worklets own overlay opacity and pointer events while +The gesture hosts stay mounted. The Gesture Handler web patch keeps initially disabled hosts +from capturing paragraph pointers; that capture confines browser selection to its starting paragraph. +Native worklets own overlay opacity and pointer events while React owns settled panel activity and accessibility. Keep hidden native overlays laid out: collapsing their scroll ranges makes Android spring retained offsets back to zero during touch cancellation or release. Native panel hosts and their dependent draggable lists diff --git a/docs/testing.md b/docs/testing.md index 8b1565d86d..afe7ceade8 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -193,7 +193,7 @@ Test suites in this repo are heavy. Running them in bulk freezes the machine, es - Playwright specs that exercise only the daemon import `daemonTest` from the shared fixtures so they do not create a browser context or page. - Helpers that create projects or workspaces own those records until cleanup. Their clients remove the daemon project on close, and an automatic fixture fails any test that still leaks a project record. Deleting only the temporary directory is not cleanup. Agent helpers pass the intended `workspaceId` through to agent creation; they never infer ownership from `cwd`. - Tests whose subject is daemon-global state, such as an empty history or daemon restart, start a dedicated host explicitly. Filenames and directories describe product behavior, never execution order or isolation mechanics. -- Global setup accepts Metro as ready only when `/status` returns `packager-status:running`, then fetches the document's scripts so the cold bundle compilation finishes before Playwright's per-test timeout starts. A generic TCP listener is not sufficient readiness evidence. The browser suite uses direct local daemon connections and does not start a relay. +- Global setup accepts Metro as ready only when `/status` returns `packager-status:running`, then fetches the document's scripts so the cold bundle compilation finishes before Playwright's per-test timeout starts. A generic TCP listener is not sufficient readiness evidence. The browser suite uses direct local daemon connections and does not start a relay. Automated Metro launches set `EXPO_UNSTABLE_HEADLESS=1` so Expo does not download the native DevTools shell into temporary test homes; its read-only cache breaks teardown. Browser fixtures and the standalone Electron browser runner share the developer-toast dismissal helper while retaining console logs. A pointer click moves hover away from the tested control and stalls behind app modal backdrops. - The app Playwright harness boots on Windows as well as POSIX. Spawn Node entrypoints through `process.execPath`, not `npx` or `node_modules/.bin` shims: Node refuses to spawn `.cmd` or `.bat` without `shell: true`, and shell mode concatenates argv without escaping and sends kill signals to `cmd.exe` instead of the real child. - Teardown kills the process tree, because a Windows signal reaches only the direct child and leaves forked workers holding the listening port. - The `asdf`-backed local Elixir relay stays POSIX-only, so the `relay-deployment` Playwright project is unavailable on Windows. diff --git a/package-lock.json b/package-lock.json index 81248c6c1d..98566a2ec0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "oxlint-tsgolint": "^0.22.1", "patch-package": "^8.0.1", "playwright": "^1.56.1", + "react-dom": "19.2.3", "typescript": "^5.9.3", "ws": "^8.20.0" } @@ -47,6 +48,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@0no-co/graphql.web/-/graphql.web-1.2.0.tgz", "integrity": "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw==", + "dev": true, "license": "MIT", "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" @@ -740,6 +742,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -755,6 +758,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -767,6 +771,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -781,6 +786,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -790,12 +796,14 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, "license": "MIT" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -805,6 +813,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -814,6 +823,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -970,6 +980,7 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -982,6 +993,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -994,6 +1006,7 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -1006,6 +1019,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1094,6 +1108,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz", "integrity": "sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -1109,6 +1124,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -1121,6 +1137,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1148,6 +1165,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -1172,6 +1190,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -1184,6 +1203,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1196,6 +1216,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -1220,6 +1241,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1235,6 +1257,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -1414,6 +1437,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.28.6.tgz", "integrity": "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -1592,6 +1616,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", @@ -1625,6 +1650,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -1787,6 +1813,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.28.6.tgz", "integrity": "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" @@ -2120,6 +2147,7 @@ "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.28.6.tgz", "integrity": "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", @@ -2136,6 +2164,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -2391,6 +2420,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", @@ -2467,25 +2497,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse--for-generate-function-map": { - "name": "@babel/traverse", - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/types": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", @@ -3913,6 +3924,12 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@expo-google-fonts/material-symbols": { + "version": "0.4.50", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.50.tgz", + "integrity": "sha512-XNSgSfd+1p6wqRAzzhrckGngHJQ1/z+oCMdI5FN+x/VnDeMMFGkXsuRNPYcZTYYff1GwVwx4u6Gqnb30aALysw==", + "license": "MIT AND Apache-2.0" + }, "node_modules/@expo/apple-utils": { "version": "2.1.13", "resolved": "https://registry.npmjs.org/@expo/apple-utils/-/apple-utils-2.1.13.tgz", @@ -3947,35 +3964,37 @@ } }, "node_modules/@expo/cli": { - "version": "54.0.23", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.23.tgz", - "integrity": "sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g==", + "version": "57.0.31", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.31.tgz", + "integrity": "sha512-NPTMPGQ9i3KzULyP1bzp8hMggoe3QlkfICw388zJuj0UhqfGHEZURkJFuHBksb/ndTjfrCrCBOO0HQz/9QzXIw==", "license": "MIT", "dependencies": { - "@0no-co/graphql.web": "^1.0.8", "@expo/code-signing-certificates": "^0.0.6", - "@expo/config": "~12.0.13", - "@expo/config-plugins": "~54.0.4", + "@expo/config": "~57.0.10", + "@expo/config-plugins": "~57.0.10", "@expo/devcert": "^1.2.1", - "@expo/env": "~2.0.8", - "@expo/image-utils": "^0.8.8", - "@expo/json-file": "^10.0.8", - "@expo/metro": "~54.2.0", - "@expo/metro-config": "~54.0.14", - "@expo/osascript": "^2.3.8", - "@expo/package-manager": "^1.9.10", - "@expo/plist": "^0.4.8", - "@expo/prebuild-config": "^54.0.8", - "@expo/schema-utils": "^0.1.8", - "@expo/spawn-async": "^1.7.2", - "@expo/ws-tunnel": "^1.0.1", - "@expo/xcpretty": "^4.3.0", - "@react-native/dev-middleware": "0.81.5", - "@urql/core": "^5.0.6", - "@urql/exchange-retry": "^1.3.0", + "@expo/env": "~2.4.3", + "@expo/image-utils": "^0.11.6", + "@expo/inline-modules": "^0.1.8", + "@expo/json-file": "^11.0.1", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.13", + "@expo/metro-file-map": "^57.0.4", + "@expo/osascript": "^2.7.1", + "@expo/package-manager": "^1.13.1", + "@expo/plist": "^0.8.1", + "@expo/prebuild-config": "^57.0.19", + "@expo/require-utils": "^57.0.6", + "@expo/router-server": "^57.0.13", + "@expo/schema-utils": "^57.0.2", + "@expo/spawn-async": "^1.8.0", + "@expo/ws-tunnel": "^2.0.0", + "@expo/xcpretty": "^4.4.4", + "@react-native/dev-middleware": "0.86.3", "accepts": "^1.3.8", + "agent-cli-detector": "0.1.7", "arg": "^5.0.2", - "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", @@ -3983,41 +4002,35 @@ "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", - "env-editor": "^0.4.1", - "expo-server": "^1.0.5", - "freeport-async": "^2.0.0", + "dnssd-advertise": "^1.1.4", + "expo-server": "^57.0.3", + "fetch-nodeshim": "^0.4.10", "getenv": "^2.0.0", "glob": "^13.0.0", - "lan-network": "^0.1.6", - "minimatch": "^9.0.0", + "lan-network": "^0.2.1", + "multitars": "^1.0.2", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", - "picomatch": "^3.0.1", - "pretty-bytes": "^5.6.0", + "picomatch": "^4.0.4", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", - "qrcode-terminal": "0.11.0", - "require-from-string": "^2.0.2", - "requireg": "^0.2.2", - "resolve": "^1.22.2", "resolve-from": "^5.0.0", - "resolve.exports": "^2.0.3", + "sandbox-cli-detector": "^0.2.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", - "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", - "tar": "^7.5.2", "terminal-link": "^2.1.1", - "undici": "^6.18.2", + "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", - "ws": "^8.12.1" + "ws": "^8.12.1", + "zod": "^3.25.76" }, "bin": { - "expo-internal": "build/bin/cli" + "expo-internal": "main.js" }, "peerDependencies": { "expo": "*", @@ -4043,95 +4056,93 @@ } }, "node_modules/@expo/cli/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.10.tgz", + "integrity": "sha512-YpexTqLWEXdbbXgHh7Zhpq+qA5diuvO46lb7TiY81JwqKLAl9zK31APY1D7jUFlDX56owje5RtK0o5bMmGIMUg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", + "@expo/config-plugins": "~57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.6", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" + "slugify": "^1.3.4" } }, "node_modules/@expo/cli/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", "license": "MIT", "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", - "resolve-from": "^5.0.0", "semver": "^7.5.4", - "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, - "node_modules/@expo/cli/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", - "license": "MIT" - }, - "node_modules/@expo/cli/node_modules/@expo/config/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "node_modules/@expo/cli/node_modules/@expo/config-plugins/node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" } }, + "node_modules/@expo/cli/node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, "node_modules/@expo/cli/node_modules/@expo/env": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.11.tgz", - "integrity": "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.4.3.tgz", + "integrity": "sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==", "license": "MIT", "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" } }, "node_modules/@expo/cli/node_modules/@expo/image-utils": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.12.tgz", - "integrity": "sha512-3KguH7kyKqq7pNwLb9j6BBdD/bjmNwXZG/HPWT6GWIXbwrvAJt2JNyYTP5agWJ8jbbuys1yuCzmkX+TU6rmI7A==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.11.6.tgz", + "integrity": "sha512-rmMpn7QGp6pUGRCQ3vvB9RP/vqq2q/PpToRh4dL/FbhSZOLZ1YTotpuLHf71FGOEfgKil/4PCd3hkWe/CCeiEg==", "license": "MIT", "dependencies": { - "@expo/spawn-async": "^1.7.2", + "@expo/require-utils": "^57.0.6", + "@expo/spawn-async": "^1.8.0", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", - "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, "node_modules/@expo/cli/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", @@ -4139,82 +4150,76 @@ } }, "node_modules/@expo/cli/node_modules/@expo/osascript": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.4.2.tgz", - "integrity": "sha512-/XP7PSYF2hzOZzqfjgkoWtllyeTN8dW3aM4P6YgKcmmPikKL5FdoyQhti4eh6RK5a5VrUXJTOlTNIpIHsfB5Iw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.8.1.tgz", + "integrity": "sha512-SCi+6q6uOkGhiAn6AIP/OPFgaIq/iKD2oYpnAOg2rShHStJ8ey7wyT127RbOaZXmlcY/62rHOX1WiiMnD8u/BA==", "license": "MIT", "dependencies": { - "@expo/spawn-async": "^1.7.2" + "@expo/spawn-async": "^1.8.0" }, "engines": { "node": ">=12" } }, + "node_modules/@expo/cli/node_modules/@expo/package-manager": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.14.2.tgz", + "integrity": "sha512-sftl0eRVVCarI6grMdjAB3jX2pX1Mt3cdSnajlXS4QyeDkaKRM/ntBy6dcagj1VL0+cEfEqctlyvinmlZdNubg==", + "license": "MIT", + "dependencies": { + "@expo/json-file": "^11.2.1", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" + } + }, "node_modules/@expo/cli/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", + "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "node_modules/@expo/cli/node_modules/@expo/prebuild-config": { - "version": "54.0.8", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-54.0.8.tgz", - "integrity": "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg==", + "version": "57.0.19", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-57.0.19.tgz", + "integrity": "sha512-trBpySOP8Pv/xtMSb5ASAL5y8h6kbZTinakZ5cUbu0lX5iDpiB3Cg3ANYc3coriH7jpl3cJecG4e0PzUMced8g==", "license": "MIT", "dependencies": { - "@expo/config": "~12.0.13", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/image-utils": "^0.8.8", - "@expo/json-file": "^10.0.8", - "@react-native/normalize-colors": "0.81.5", + "@expo/config": "~57.0.10", + "@expo/config-plugins": "~57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/image-utils": "^0.11.6", + "@expo/json-file": "^11.0.1", + "@react-native/normalize-colors": "0.86.3", "debug": "^4.3.1", + "expo-modules-autolinking": "~57.0.16", "resolve-from": "^5.0.0", - "semver": "^7.6.0", - "xml2js": "0.6.0" - }, - "peerDependencies": { - "expo": "*" + "semver": "^7.6.0" } }, - "node_modules/@expo/cli/node_modules/@react-native/normalize-colors": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", - "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", - "license": "MIT" - }, - "node_modules/@expo/cli/node_modules/@urql/core": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@urql/core/-/core-5.2.0.tgz", - "integrity": "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A==", + "node_modules/@expo/cli/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", "license": "MIT", "dependencies": { - "@0no-co/graphql.web": "^1.0.13", - "wonka": "^6.3.2" - } - }, - "node_modules/@expo/cli/node_modules/@urql/exchange-retry": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@urql/exchange-retry/-/exchange-retry-1.3.2.tgz", - "integrity": "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg==", - "license": "MIT", - "dependencies": { - "@urql/core": "^5.1.2", - "wonka": "^6.3.2" + "cross-spawn": "^7.0.6" }, - "peerDependencies": { - "@urql/core": "^5.0.0" + "engines": { + "node": ">=12" } }, "node_modules/@expo/cli/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -4250,13 +4255,16 @@ "node": "18 || 20 || >=22" } }, - "node_modules/@expo/cli/node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", + "node_modules/@expo/cli/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, "engines": { - "node": ">=18" + "node": "20 || >=22" } }, "node_modules/@expo/cli/node_modules/cli-cursor": { @@ -4286,27 +4294,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, - "node_modules/@expo/cli/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@expo/cli/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, "node_modules/@expo/cli/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -4342,33 +4329,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/cli/node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@expo/cli/node_modules/glob/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@expo/cli/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4405,9 +4365,9 @@ } }, "node_modules/@expo/cli/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -4423,36 +4383,24 @@ } }, "node_modules/@expo/cli/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.8" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/cli/node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@expo/cli/node_modules/node-forge": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", - "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" @@ -4517,26 +4465,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/cli/node_modules/picomatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", - "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@expo/cli/node_modules/qrcode-terminal": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", - "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, "node_modules/@expo/cli/node_modules/restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -4556,15 +4484,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, - "node_modules/@expo/cli/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/@expo/cli/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -4577,28 +4496,6 @@ "node": ">=6" } }, - "node_modules/@expo/cli/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/@expo/cli/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4611,31 +4508,6 @@ "node": ">=4" } }, - "node_modules/@expo/cli/node_modules/tar": { - "version": "7.5.11", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", - "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@expo/cli/node_modules/undici": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", - "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/@expo/cli/node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -4645,13 +4517,13 @@ "node": ">=8.0" } }, - "node_modules/@expo/cli/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" + "node_modules/@expo/cli/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/@expo/code-signing-certificates": { @@ -4771,9 +4643,9 @@ } }, "node_modules/@expo/devcert": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.1.tgz", - "integrity": "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@expo/devcert/-/devcert-1.2.2.tgz", + "integrity": "sha512-wz1YedXwdNbYqk/PRr34vixnuw1+l6uSwmPXUj649cot5iYNccb2zIOnK7Nonb1Pfd/dxAY6CvU6KM3uSdxC7A==", "license": "MIT", "dependencies": { "@expo/sudo-prompt": "^9.3.1", @@ -4790,9 +4662,9 @@ } }, "node_modules/@expo/devtools": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-0.1.8.tgz", - "integrity": "sha512-SVLxbuanDjJPgc0sy3EfXUMLb/tXzp6XIHkhtPVmTWJAp+FOr6+5SeiCfJrCzZFet0Ifyke2vX3sFcKwEvCXwQ==", + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-57.0.1.tgz", + "integrity": "sha512-GyUf+wFNkbttaX0jR7MZa9bm77U0IrLg6d2AjpxdyoXw/w4abHoXG0oFufwLMgP9zLTd5+Ct4X/ffNUTnlzZgg==", "license": "MIT", "dependencies": { "chalk": "^4.1.2" @@ -4810,6 +4682,17 @@ } } }, + "node_modules/@expo/dom-webview": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-57.0.1.tgz", + "integrity": "sha512-lAKsME4SAq+8sf56oN0DX5TBYyruupoRxbWbD2xf9RnKY8y6x8eb9LCE5pxSN0qyWdqnp+0wmyWzDkKboThKAw==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/@expo/eas-build-job": { "version": "1.0.243", "resolved": "https://registry.npmjs.org/@expo/eas-build-job/-/eas-build-job-1.0.243.tgz", @@ -5067,21 +4950,27 @@ "node": ">=6" } }, + "node_modules/@expo/expo-modules-macros-plugin": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@expo/expo-modules-macros-plugin/-/expo-modules-macros-plugin-0.6.1.tgz", + "integrity": "sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==", + "license": "MIT" + }, "node_modules/@expo/fingerprint": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.15.4.tgz", - "integrity": "sha512-eYlxcrGdR2/j2M6pEDXo9zU9KXXF1vhP+V+Tl+lyY+bU8lnzrN6c637mz6Ye3em2ANy8hhUR03Raf8VsT9Ogng==", + "version": "0.20.14", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.20.14.tgz", + "integrity": "sha512-7sihStGX1ZepJBNbYgeQY7cU2GQ+PSkSROe3g7JOQqnT6OOuX0rXKY0ZNoVnlB2Y/H5FWnnJ6QrPlK3fNg9+bQ==", "license": "MIT", "dependencies": { - "@expo/spawn-async": "^1.7.2", + "@expo/env": "^2.4.3", + "@expo/spawn-async": "^1.8.0", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", - "minimatch": "^9.0.0", - "p-limit": "^3.1.0", + "minimatch": "^10.2.2", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, @@ -5089,6 +4978,32 @@ "fingerprint": "bin/cli.js" } }, + "node_modules/@expo/fingerprint/node_modules/@expo/env": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.5.2.tgz", + "integrity": "sha512-z8kCvBVJpd2S20a+Ab1otQgz8sJLeR7CXDTsuAMcNbYFsK10Fdhfb7rx9Ys1vvlbijnY55eZhQvJACajc1IjBQ==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" + } + }, + "node_modules/@expo/fingerprint/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@expo/fingerprint/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -5098,6 +5013,18 @@ "node": "18 || 20 || >=22" } }, + "node_modules/@expo/fingerprint/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@expo/fingerprint/node_modules/getenv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", @@ -5124,33 +5051,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/fingerprint/node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@expo/fingerprint/node_modules/glob/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@expo/fingerprint/node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5161,24 +5061,24 @@ } }, "node_modules/@expo/fingerprint/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/@expo/fingerprint/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.8" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5245,6 +5145,168 @@ "node": ">= 10.0.0" } }, + "node_modules/@expo/inline-modules": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@expo/inline-modules/-/inline-modules-0.1.8.tgz", + "integrity": "sha512-5OCHzv/VHVuam9UT6/yeArtUnmkp5VdAH6k4JwdRzK/34ukzdjQK7B9n71fiswZKtm2MmZlPuy4hJo2Ao8CZNw==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.10" + } + }, + "node_modules/@expo/inline-modules/node_modules/@expo/config-plugins": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/inline-modules/node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, + "node_modules/@expo/inline-modules/node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/inline-modules/node_modules/@expo/plist": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/inline-modules/node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@expo/inline-modules/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@expo/inline-modules/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@expo/inline-modules/node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@expo/inline-modules/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/inline-modules/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@expo/inline-modules/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/inline-modules/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/inline-modules/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, "node_modules/@expo/json-file": { "version": "8.3.3", "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-8.3.3.tgz", @@ -5267,6 +5329,222 @@ "@babel/highlight": "^7.10.4" } }, + "node_modules/@expo/local-build-cache-provider": { + "version": "57.0.9", + "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-57.0.9.tgz", + "integrity": "sha512-hox13/K/dqvKG7StLYs9nwyNR/mJ5ieAkNN8jTee6liMPyUQTfpzgticRyWnVxj49Fr8PpTaQab/ArYVEBJOcQ==", + "license": "MIT", + "dependencies": { + "@expo/config": "~57.0.10", + "chalk": "^4.1.2" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/config": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.10.tgz", + "integrity": "sha512-YpexTqLWEXdbbXgHh7Zhpq+qA5diuvO46lb7TiY81JwqKLAl9zK31APY1D7jUFlDX56owje5RtK0o5bMmGIMUg==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.6", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.6.0", + "slugify": "^1.3.4" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/config-plugins": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/config-plugins/node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@expo/plist": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@expo/local-build-cache-provider/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "node_modules/@expo/log-box": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-57.0.4.tgz", + "integrity": "sha512-IxwS9s1L2muj8mj8AQSuiy7u8OFJdc02NRFo2me/Tj6DiaeG5SREqmpBE4rQpR2cadqSg5jl8Qab8Cjie616dg==", + "license": "MIT", + "dependencies": { + "@expo/dom-webview": "^57.0.1", + "anser": "^1.4.9", + "stacktrace-parser": "^0.1.10" + }, + "peerDependencies": { + "@expo/dom-webview": "^57.0.1", + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "node_modules/@expo/log-box-utils": { + "version": "58.0.2", + "resolved": "https://registry.npmjs.org/@expo/log-box-utils/-/log-box-utils-58.0.2.tgz", + "integrity": "sha512-My8Lwe9FU/yDwwzqwi5LN2rzzDcJqIAZKrD9f0XHZEKz/FQnWJYdt1rsV7+RwqMGeGq2XsxTCVT1ggTCOvumxw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@expo/logger": { "version": "1.0.221", "resolved": "https://registry.npmjs.org/@expo/logger/-/logger-1.0.221.tgz", @@ -5279,53 +5557,55 @@ } }, "node_modules/@expo/metro": { - "version": "54.2.0", - "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-54.2.0.tgz", - "integrity": "sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w==", + "version": "56.0.2", + "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-56.0.2.tgz", + "integrity": "sha512-Ld5AeYMCCDa8bLeWhfuLbZFFjlV3f6ORqyPz2glGh6RltIngMuLf9BTC2yvHFjkKuGxL5SynijmA8xmNNWn5iA==", "license": "MIT", "dependencies": { - "metro": "0.83.3", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-config": "0.83.3", - "metro-core": "0.83.3", - "metro-file-map": "0.83.3", - "metro-minify-terser": "0.83.3", - "metro-resolver": "0.83.3", - "metro-runtime": "0.83.3", - "metro-source-map": "0.83.3", - "metro-symbolicate": "0.83.3", - "metro-transform-plugins": "0.83.3", - "metro-transform-worker": "0.83.3" + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5" } }, "node_modules/@expo/metro-config": { - "version": "54.0.14", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-54.0.14.tgz", - "integrity": "sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA==", + "version": "57.0.13", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-57.0.13.tgz", + "integrity": "sha512-r+YCwqh8FM5cymkC3MdYO32DqLZQ2wDWkGEnzwgwI40Bj355BvL4XoY0hGgao9vNHjYa7be7XxbVqtMTi76snw==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", - "@expo/config": "~12.0.13", - "@expo/env": "~2.0.8", - "@expo/json-file": "~10.0.8", - "@expo/metro": "~54.2.0", - "@expo/spawn-async": "^1.7.2", + "@expo/config": "~57.0.10", + "@expo/env": "~2.4.3", + "@expo/json-file": "~11.0.1", + "@expo/metro": "~56.0.2", + "@expo/require-utils": "^57.0.6", + "@expo/spawn-async": "^1.8.0", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^13.0.0", - "hermes-parser": "^0.29.1", + "hermes-parser": "^0.36.0", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", - "minimatch": "^9.0.0", - "postcss": "~8.4.32", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", "resolve-from": "^5.0.0" }, "peerDependencies": { @@ -5338,80 +5618,68 @@ } }, "node_modules/@expo/metro-config/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.10.tgz", + "integrity": "sha512-YpexTqLWEXdbbXgHh7Zhpq+qA5diuvO46lb7TiY81JwqKLAl9zK31APY1D7jUFlDX56owje5RtK0o5bMmGIMUg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", + "@expo/config-plugins": "~57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.6", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" + "slugify": "^1.3.4" } }, "node_modules/@expo/metro-config/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", "license": "MIT", "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", - "resolve-from": "^5.0.0", "semver": "^7.5.4", - "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "node_modules/@expo/metro-config/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", "license": "MIT" }, - "node_modules/@expo/metro-config/node_modules/@expo/config/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/@expo/metro-config/node_modules/@expo/env": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.11.tgz", - "integrity": "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.4.3.tgz", + "integrity": "sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==", "license": "MIT", "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" } }, "node_modules/@expo/metro-config/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", @@ -5419,20 +5687,32 @@ } }, "node_modules/@expo/metro-config/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", + "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, + "node_modules/@expo/metro-config/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@expo/metro-config/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -5447,25 +5727,16 @@ "node": "18 || 20 || >=22" } }, - "node_modules/@expo/metro-config/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/@expo/metro-config/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/@expo/metro-config/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" + "dependencies": { + "balanced-match": "^4.0.2" }, - "funding": { - "url": "https://dotenvx.com" + "engines": { + "node": "20 || >=22" } }, "node_modules/@expo/metro-config/node_modules/getenv": { @@ -5494,52 +5765,40 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/metro-config/node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "node_modules/@expo/metro-config/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "license": "MIT" + }, + "node_modules/@expo/metro-config/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@expo/metro-config/node_modules/glob/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "hermes-estree": "0.36.1" } }, "node_modules/@expo/metro-config/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/@expo/metro-config/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "license": "ISC", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.8" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5561,37 +5820,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@expo/metro-config/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@expo/metro-config/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/@expo/metro-config/node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -5601,18 +5829,33 @@ "node": ">=8.0" } }, - "node_modules/@expo/metro-runtime": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-6.1.2.tgz", - "integrity": "sha512-nvM+Qv45QH7pmYvP8JB1G8JpScrWND3KrMA6ZKe62cwwNiX/BjHU28Ear0v/4bQWXlOY0mv6B8CDIm8JxXde9g==", + "node_modules/@expo/metro-file-map": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-57.0.4.tgz", + "integrity": "sha512-gLABIbU3SlxRVVCe56ZfYFbxjhdpAKomQYr6LIeDYf7rca8Pfvzv8FS39hH0+IcdpEHly2Jy0X2nd4/obd8Kig==", "license": "MIT", "dependencies": { + "debug": "^4.3.4", + "fb-watchman": "^2.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "walker": "^1.0.8" + } + }, + "node_modules/@expo/metro-runtime": { + "version": "57.0.17", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-57.0.17.tgz", + "integrity": "sha512-fiWYLaMDV8hoIpyPztRFPhGbHCHWlVfRTac3jZV7tP+fYCpo1QmgsuL23ubnoWqDZhFuRDNk+hQ4y21DMmxEFA==", + "license": "MIT", + "dependencies": { + "@expo/log-box": "^57.0.4", "anser": "^1.4.9", "pretty-format": "^29.7.0", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0" }, "peerDependencies": { + "@expo/log-box": "^57.0.4", "expo": "*", "react": "*", "react-dom": "*", @@ -5624,6 +5867,68 @@ } } }, + "node_modules/@expo/metro/node_modules/metro-config": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.5.tgz", + "integrity": "sha512-zie+uN6oohscowi2S7ByU+wUw6CrT4ZxW9uAbONOObSxx86RGmnIAmjXHLkfmcdYoY7jzOPEbqcI6oeVmqyBQA==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.5", + "metro-cache": "0.84.5", + "metro-core": "0.84.5", + "metro-runtime": "0.84.5", + "yaml": "^2.6.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@expo/metro/node_modules/metro-runtime": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.5.tgz", + "integrity": "sha512-U1m2+d1Pr+JO2/iVXBB2OfXXityz7tqwIorxfrT15IEgaHvpJBq/OHiqnOWPKJbUl3JcxjcdviZZOKk85oK4Qg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@expo/modules-macros-win32-arm64": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@expo/modules-macros-win32-arm64/-/modules-macros-win32-arm64-0.20.0.tgz", + "integrity": "sha512-7B57gc7+TeygPcK8fLYlEhJbbvaPh+JBzex11YIYZrSzbFhz7Q+Z37fSdAfp4EsfCswJNcX0S6wpkgSlVNefVw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, + "node_modules/@expo/modules-macros-win32-x64": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@expo/modules-macros-win32-x64/-/modules-macros-win32-x64-0.20.0.tgz", + "integrity": "sha512-BM5a2U2tCyHzmtiSEY70KPsts82Mfy1bHSZ7AUbg6z9LcnxuThxJlcH85/SV5eFbhrPfgDBAG/WAncyZCvKvyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true + }, "node_modules/@expo/multipart-body-parser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@expo/multipart-body-parser/-/multipart-body-parser-2.0.0.tgz", @@ -5675,6 +5980,7 @@ "version": "1.9.10", "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.9.10.tgz", "integrity": "sha512-axJm+NOj3jVxep49va/+L3KkF3YW/dkV+RwzqUJedZrv4LeTqOG4rhrCaCPXHTvLqCTDKu6j0Xyd28N7mnxsGA==", + "dev": true, "license": "MIT", "dependencies": { "@expo/json-file": "^10.0.8", @@ -5689,6 +5995,7 @@ "version": "10.0.12", "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", @@ -5699,6 +6006,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -5708,6 +6016,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" @@ -5720,6 +6029,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, "license": "MIT", "dependencies": { "restore-cursor": "^2.0.0" @@ -5732,6 +6042,7 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" @@ -5741,12 +6052,14 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, "license": "MIT" }, "node_modules/@expo/package-manager/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" @@ -5756,6 +6069,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5765,6 +6079,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^2.0.1" @@ -5777,6 +6092,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -5791,6 +6107,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5800,6 +6117,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^1.0.0" @@ -5812,6 +6130,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^2.4.2", @@ -5829,6 +6148,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", @@ -5843,6 +6163,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, "license": "MIT", "dependencies": { "onetime": "^2.0.0", @@ -5856,12 +6177,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/@expo/package-manager/node_modules/strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^4.1.0" @@ -5874,6 +6197,7 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" @@ -5892,6 +6216,14 @@ "node-forge": "^1.2.1" } }, + "node_modules/@expo/platforms": { + "version": "58.0.1", + "resolved": "https://registry.npmjs.org/@expo/platforms/-/platforms-58.0.1.tgz", + "integrity": "sha512-KtLrtAvpShq16l9lTxd2fZSjULxcGxXrJTHA31iUVqrc+Af7aTAJW4ZB3yQBgi/w+kSb6BB/CG9RXI0ohbMm6g==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@expo/plist": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.2.0.tgz", @@ -6129,6 +6461,25 @@ "node": ">=10" } }, + "node_modules/@expo/require-utils": { + "version": "57.0.6", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-57.0.6.tgz", + "integrity": "sha512-PKWfFdMgwWrlSP6NGplCi2nK0dEM5MeJ2Cj1ijr5VWTmZ+pKsJsJw2dWkBtlFDyxMY8eUjCPZ7hoqFEnbc0Pcw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@expo/results": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@expo/results/-/results-1.0.0.tgz", @@ -6139,6 +6490,40 @@ "node": ">=10" } }, + "node_modules/@expo/router-server": { + "version": "57.0.13", + "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-57.0.13.tgz", + "integrity": "sha512-A25869lSp6916GiYjz1y1S/Kfi5qn7S1xepycFv8x8VOrulLBbv0byXl6o3BSLh5nLBx5RiMTjBFM2u+K7JsrA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "@expo/metro-runtime": "^57.0.17", + "expo": "*", + "expo-constants": "^57.0.22", + "expo-font": "^57.0.4", + "expo-router": "*", + "expo-server": "^57.0.3", + "react": "*", + "react-dom": "*", + "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" + }, + "peerDependenciesMeta": { + "@expo/metro-runtime": { + "optional": true + }, + "expo-router": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, "node_modules/@expo/rudder-sdk-node": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@expo/rudder-sdk-node/-/rudder-sdk-node-1.1.1.tgz", @@ -6169,9 +6554,9 @@ } }, "node_modules/@expo/schema-utils": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-0.1.8.tgz", - "integrity": "sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-57.0.2.tgz", + "integrity": "sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw==", "license": "MIT" }, "node_modules/@expo/sdk-runtime-versions": { @@ -6184,6 +6569,7 @@ "version": "1.7.2", "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.7.2.tgz", "integrity": "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3" @@ -6271,28 +6657,49 @@ "dev": true, "license": "MIT" }, - "node_modules/@expo/vector-icons": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-15.1.1.tgz", - "integrity": "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw==", + "node_modules/@expo/ui": { + "version": "57.0.25", + "resolved": "https://registry.npmjs.org/@expo/ui/-/ui-57.0.25.tgz", + "integrity": "sha512-/BbxsKh/LSIFDnWAHRHfJdCcnqHY7WNcWXjld0soKnYXDUbImjvsFK7y5dqq2XZTbOMyf44BpgAWKUR/B8huCA==", "license": "MIT", + "dependencies": { + "sf-symbols-typescript": "^2.1.0", + "vaul": "^1.1.2" + }, "peerDependencies": { - "expo-font": ">=14.0.4", + "@babel/core": "*", + "expo": "*", "react": "*", - "react-native": "*" + "react-dom": "*", + "react-native": "*", + "react-native-worklets": "*" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-worklets": { + "optional": true + } } }, "node_modules/@expo/ws-tunnel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz", - "integrity": "sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q==", - "license": "MIT" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-2.0.1.tgz", + "integrity": "sha512-mljsRffbOHzmSimYQbQu9h9NR3alwCCwEEouRGFL4QRTt8dNvsNtKEPa/5jHmtDLDtsh4xXsWKwzjN9BTpeXHQ==", + "license": "MIT", + "peerDependencies": { + "ws": "^8.0.0" + } }, "node_modules/@expo/xcpretty": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.1.tgz", - "integrity": "sha512-KZNxZvnGCtiM2aYYZ6Wz0Ix5r47dAvpNLApFtZWnSoERzAdOMzVBOPysBoM0JlF6FKWZ8GPqgn6qt3dV/8Zlpg==", - "license": "BSD-3-Clause", + "version": "4.4.7", + "resolved": "https://registry.npmjs.org/@expo/xcpretty/-/xcpretty-4.4.7.tgz", + "integrity": "sha512-EbxYllZ7/ozONVZd425cm4XnolfW+AmSFT5aP7Jdno6oc3WrYQcHz2CO20z/2rwWwYgztmV2PXvYH+BQ8YFjqg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", "chalk": "^4.1.0", @@ -6568,12 +6975,6 @@ "import-meta-resolve": "^4.2.0" } }, - "node_modules/@ide/backoff": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz", - "integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==", - "license": "MIT" - }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", @@ -7146,6 +7547,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.4" @@ -7167,6 +7569,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -7183,6 +7586,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -7192,6 +7596,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -7205,6 +7610,7 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -7218,6 +7624,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -7230,6 +7637,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -7245,6 +7653,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -7257,6 +7666,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7294,6 +7704,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3" @@ -7316,6 +7727,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", @@ -7358,6 +7770,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -7429,6 +7842,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", @@ -7455,12 +7869,14 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, "license": "ISC" }, "node_modules/@jest/transform/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7470,6 +7886,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -8436,6 +8853,150 @@ "node": ">=12.4.0" } }, + "node_modules/@noxcturnal/noxcturnal-darwin-arm64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-darwin-arm64/-/noxcturnal-darwin-arm64-0.1.5.tgz", + "integrity": "sha512-hQgDaWxKYln83Uk1Hh4Liju9AvGoYh4aLd4A1ou3lGn5hxzhW2uO+z3mERtWk6BMGVazvi/yUXtp9x3IlaWyhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-darwin-x64": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-darwin-x64/-/noxcturnal-darwin-x64-0.1.5.tgz", + "integrity": "sha512-I57zR8QF7Xam+4nGD5UoIODsw0VjkVyn51iDBL3CMaDR5Lh1OxXwKZMYKtv3CtQl+RSDsMfmXBEqGYLE8lIPHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-linux-arm64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-linux-arm64-gnu/-/noxcturnal-linux-arm64-gnu-0.1.5.tgz", + "integrity": "sha512-gVH4XJPh8RdrdjjlU0dKeielQt/FXfvqhr8IEWEf3VeNtQs8l2rPzFPdqS0uwLWQYHLBGgB0LkuOil1KKYx1gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-linux-arm64-musl": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-linux-arm64-musl/-/noxcturnal-linux-arm64-musl-0.1.5.tgz", + "integrity": "sha512-rzQ075fcHZ+ebsELussRjnW8WBMy1RuLdS8wSqBGhdVlPR7/NaSyoWkNxnVDT8sEO26xjqGoW/o/08ghBzr/zA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-linux-x64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-linux-x64-gnu/-/noxcturnal-linux-x64-gnu-0.1.5.tgz", + "integrity": "sha512-X5O0lXMrv8HGOGoXDB1PG0Hjt7Rl+MJA+seR2NecQvUAAw2gzDvF/unCV5sqTAVeHfXhBHEFGkLenHZSD44efg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-linux-x64-musl": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-linux-x64-musl/-/noxcturnal-linux-x64-musl-0.1.5.tgz", + "integrity": "sha512-fkQIQHRxqldNXVmjxfeCvGOiLhLU9SLBw1As02pMA2xjyiZfiXcUn4SUrZ92ciGnyCS8/XMbx+nZSxgEc3qDPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-win32-arm64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-win32-arm64-msvc/-/noxcturnal-win32-arm64-msvc-0.1.5.tgz", + "integrity": "sha512-baeH5m/vM1nf0J2UkW8cfgiVogpM0gRO9b4PZWknXQPbv5+k+0N5sGOYl/UAO2q72qYb3Xbiu7eD8c4A2kR2SA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@noxcturnal/noxcturnal-win32-x64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@noxcturnal/noxcturnal-win32-x64-msvc/-/noxcturnal-win32-x64-msvc-0.1.5.tgz", + "integrity": "sha512-2faDMzom8pCG/s/uR4Czh1atz4KohI85AaSmA2vtAuVnCq+nLL4Viys3A5vUlNz9MNBmTNFxzXyF2Z5HtfxXLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@npmcli/agent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", @@ -8787,6 +9348,17 @@ "node": ">=8.0.0" } }, + "node_modules/@oxc-project/types": { + "version": "0.154.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.154.0.tgz", + "integrity": "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==", + "dev": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/oxc-project" + } + }, "node_modules/@oxc-resolver/binding-android-arm-eabi": { "version": "11.19.1", "resolved": "https://registry.npmjs.org/@oxc-resolver/binding-android-arm-eabi/-/binding-android-arm-eabi-11.19.1.tgz", @@ -10409,19 +10981,31 @@ "react-native": ">=0.57" } }, + "node_modules/@react-native/asset-utils": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/asset-utils/-/asset-utils-0.88.0.tgz", + "integrity": "sha512-Bj1DxQt5f4OrjdlgSVkZT37Z3hx5hUIN5AUDSqL/e99vgtTcqj5vnm067epZL1EF/QiqsniZO8Q1GSkItOakDg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, "node_modules/@react-native/assets-registry": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.5.tgz", - "integrity": "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.86.3.tgz", + "integrity": "sha512-TDhgCZA4wjJg84d5A9swiOQYPIWSKEEVdg9IwMFZDupQzW/F3QoLUrfAJOcalgqTDA9/buTB8awhE3Whwg6u9Q==", "license": "MIT", "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/babel-plugin-codegen": { "version": "0.81.5", "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.81.5.tgz", "integrity": "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.3", @@ -10435,6 +11019,7 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.81.5.tgz", "integrity": "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -10494,6 +11079,7 @@ "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10503,6 +11089,7 @@ "version": "0.81.5", "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.81.5.tgz", "integrity": "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -10524,6 +11111,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -10535,6 +11123,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -10555,6 +11144,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -10563,104 +11153,101 @@ "node": "*" } }, - "node_modules/@react-native/community-cli-plugin": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.81.5.tgz", - "integrity": "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw==", - "license": "MIT", - "dependencies": { - "@react-native/dev-middleware": "0.81.5", - "debug": "^4.4.0", - "invariant": "^2.2.4", - "metro": "^0.83.1", - "metro-config": "^0.83.1", - "metro-core": "^0.83.1", - "semver": "^7.1.3" - }, - "engines": { - "node": ">= 20.19.4" - }, - "peerDependencies": { - "@react-native-community/cli": "*", - "@react-native/metro-config": "*" - }, - "peerDependenciesMeta": { - "@react-native-community/cli": { - "optional": true - }, - "@react-native/metro-config": { - "optional": true - } - } - }, "node_modules/@react-native/debugger-frontend": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.81.5.tgz", - "integrity": "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.86.3.tgz", + "integrity": "sha512-TQmeofQ0PcuylhhlleOeuzHYZfbrgm3gayXzowqUEzgRisTm1D40/J3ggqs7XkQi5HP5ZA3n8dHmKL9vIzPcsw==", "license": "BSD-3-Clause", "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/debugger-shell": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.86.3.tgz", + "integrity": "sha512-O4ds+J7xZfxkbih9T+cAGegBdvKSPKYJm/lDgC9CpEjFMkmzWTpVLU3Qsv9sqZuo58z+sGhIcJfPsCFFWHpqbQ==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/dev-middleware": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.81.5.tgz", - "integrity": "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.86.3.tgz", + "integrity": "sha512-LiEPTqTg/63bYUnrPyHLfjTDCNhA/+CUqI1+DsA9tYyewtSbULd5awsva6SgE10I+2iMhgKXS3ymkhU/kSCrGA==", "license": "MIT", "dependencies": { "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.81.5", + "@react-native/debugger-frontend": "0.86.3", + "@react-native/debugger-shell": "0.86.3", "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.2.0", + "chromium-edge-launcher": "^0.3.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", - "ws": "^6.2.3" + "ws": "^7.5.10" }, "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/dev-middleware/node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", "license": "MIT", - "dependencies": { - "async-limiter": "~1.0.0" + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/@react-native/gradle-plugin": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.81.5.tgz", - "integrity": "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.86.3.tgz", + "integrity": "sha512-lxmx0GqLEWRIpZfpYFXlYVIs3ENQwaW6Vmp6oi29l2GoQJ1wZfFZRdMimDWlGEk8LKfHar3QH3iaPMkTcK9lEQ==", "license": "MIT", "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/js-polyfills": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.81.5.tgz", - "integrity": "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.86.3.tgz", + "integrity": "sha512-eYIJ0es967+tePBFQDnl/gidVFxLns3fnbiK6rxscQrGodvuUO6hwxpQnfNynJ8MjbbndImXihXjcnJdc7SzJg==", "license": "MIT", "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/metro-babel-transformer": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.85.3.tgz", - "integrity": "sha512-omuKq+r7jM4XvCMIlNMPP7Up3SyB8o5EAdZtF7YXniKyq7UOMBqhYHFqgsdOXr0lT+3ADf7VCJG3sb82jlBrrQ==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.86.3.tgz", + "integrity": "sha512-0nlwVkG0uT9o72nrGTKUz/IqDnCkM4zE0ihe4r+OJcxH93yBdDm58AXJ3EXZeSjv3osHEFXU7ceajdZiS34mTw==", "license": "MIT", "peer": true, "dependencies": { "@babel/core": "^7.25.2", - "@react-native/babel-preset": "0.85.3", - "hermes-parser": "0.33.3", + "@react-native/babel-preset": "0.86.3", + "hermes-parser": "0.36.0", "nullthrows": "^1.1.1" }, "engines": { @@ -10671,23 +11258,23 @@ } }, "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-plugin-codegen": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.85.3.tgz", - "integrity": "sha512-Wc94zGfeFG8Njf9SHMPfYZP04kjigkOps6F1TYTvd7ZVXuGxqseCDgxc50LWcOhOCLypI9n3oVVqz81C3p44ZA==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.86.3.tgz", + "integrity": "sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==", "license": "MIT", "peer": true, "dependencies": { "@babel/traverse": "^7.29.0", - "@react-native/codegen": "0.85.3" + "@react-native/codegen": "0.86.3" }, "engines": { "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-preset": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.85.3.tgz", - "integrity": "sha512-fD7fxEhkJB/aF57tWoXjaAWpklfrExYZS3k6aXPP3BQ77DZY7gvf/b7dbirwjID6NVnP1JDRJyTuPBGr0K/vlw==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.86.3.tgz", + "integrity": "sha512-/eqs/Hy9RZRcjdcs4wj3Cqmxvtb3NM5g+Uuh1RIvsjynMO8PRsrVWWLWgBcZL/jYUo+ogXd2NFB0W8L5Bg89xw==", "license": "MIT", "peer": true, "dependencies": { @@ -10720,8 +11307,8 @@ "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@react-native/babel-plugin-codegen": "0.85.3", - "babel-plugin-syntax-hermes-parser": "0.33.3", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-syntax-hermes-parser": "0.36.0", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" }, @@ -10733,15 +11320,15 @@ } }, "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/codegen": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.3.tgz", - "integrity": "sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", + "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", "license": "MIT", "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.29.0", - "hermes-parser": "0.33.3", + "hermes-parser": "0.36.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "tinyglobby": "^0.2.15", @@ -10755,30 +11342,30 @@ } }, "node_modules/@react-native/metro-babel-transformer/node_modules/babel-plugin-syntax-hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.33.3.tgz", - "integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.0.tgz", + "integrity": "sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==", "license": "MIT", "peer": true, "dependencies": { - "hermes-parser": "0.33.3" + "hermes-parser": "0.36.0" } }, "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", - "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", "license": "MIT", "peer": true }, "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.33.3", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", - "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", "license": "MIT", "peer": true, "dependencies": { - "hermes-estree": "0.33.3" + "hermes-estree": "0.36.0" } }, "node_modules/@react-native/metro-babel-transformer/node_modules/react-refresh": { @@ -10792,14 +11379,14 @@ } }, "node_modules/@react-native/metro-config": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.85.3.tgz", - "integrity": "sha512-sVo6HepUmCcpdfozEf91lA0FjpLNNZYu/Zi9FiYiAQTK8pzATXDVTqhvdxpFrQn435p5eUTSbllvbH/KN+bnyA==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.86.3.tgz", + "integrity": "sha512-qdzDMepV2xdUhsO4XC7idnnbt8K6+Hd59AjeK9y4KS86fxSQq5oL0TAbqUuajDGR7beNQoYTuS6AowN/zP0oaQ==", "license": "MIT", "peer": true, "dependencies": { - "@react-native/js-polyfills": "0.85.3", - "@react-native/metro-babel-transformer": "0.85.3", + "@react-native/js-polyfills": "0.86.3", + "@react-native/metro-babel-transformer": "0.86.3", "metro-config": "^0.84.3", "metro-runtime": "^0.84.3" }, @@ -10807,454 +11394,28 @@ "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/metro-config/node_modules/@react-native/js-polyfills": { - "version": "0.85.3", - "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.3.tgz", - "integrity": "sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A==", - "license": "MIT", - "peer": true, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "peer": true, - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@react-native/metro-config/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@react-native/metro-config/node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@react-native/metro-config/node_modules/hermes-estree": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", - "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", - "license": "MIT", - "peer": true - }, - "node_modules/@react-native/metro-config/node_modules/hermes-parser": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", - "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", - "license": "MIT", - "peer": true, - "dependencies": { - "hermes-estree": "0.35.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "peer": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz", - "integrity": "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "accepts": "^2.0.0", - "ci-info": "^2.0.0", - "connect": "^3.6.5", - "debug": "^4.4.0", - "error-stack-parser": "^2.0.6", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "hermes-parser": "0.35.0", - "image-size": "^1.0.2", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "jsc-safe-url": "^0.2.2", - "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.84.4", - "metro-cache": "0.84.4", - "metro-cache-key": "0.84.4", - "metro-config": "0.84.4", - "metro-core": "0.84.4", - "metro-file-map": "0.84.4", - "metro-resolver": "0.84.4", - "metro-runtime": "0.84.4", - "metro-source-map": "0.84.4", - "metro-symbolicate": "0.84.4", - "metro-transform-plugins": "0.84.4", - "metro-transform-worker": "0.84.4", - "mime-types": "^3.0.1", - "nullthrows": "^1.1.1", - "serialize-error": "^2.1.0", - "source-map": "^0.5.6", - "throat": "^5.0.0", - "ws": "^7.5.10", - "yargs": "^17.6.2" - }, - "bin": { - "metro": "src/cli.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-babel-transformer": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.4.tgz", - "integrity": "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.25.2", - "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.35.0", - "metro-cache-key": "0.84.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-cache": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.4.tgz", - "integrity": "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==", - "license": "MIT", - "peer": true, - "dependencies": { - "exponential-backoff": "^3.1.1", - "flow-enums-runtime": "^0.0.6", - "https-proxy-agent": "^7.0.5", - "metro-core": "0.84.4" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-cache-key": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.4.tgz", - "integrity": "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-config": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz", - "integrity": "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "connect": "^3.6.5", - "flow-enums-runtime": "^0.0.6", - "jest-validate": "^29.7.0", - "metro": "0.84.4", - "metro-cache": "0.84.4", - "metro-core": "0.84.4", - "metro-runtime": "0.84.4", - "yaml": "^2.6.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-core": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz", - "integrity": "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "lodash.throttle": "^4.1.1", - "metro-resolver": "0.84.4" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-file-map": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.4.tgz", - "integrity": "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "debug": "^4.4.0", - "fb-watchman": "^2.0.0", - "flow-enums-runtime": "^0.0.6", - "graceful-fs": "^4.2.4", - "invariant": "^2.2.4", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "nullthrows": "^1.1.1", - "walker": "^1.0.7" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-minify-terser": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.4.tgz", - "integrity": "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "terser": "^5.15.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-resolver": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.4.tgz", - "integrity": "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-runtime": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz", - "integrity": "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "^7.25.0", - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-source-map": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz", - "integrity": "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-symbolicate": "0.84.4", - "nullthrows": "^1.1.1", - "ob1": "0.84.4", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-symbolicate": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.4.tgz", - "integrity": "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6", - "invariant": "^2.2.4", - "metro-source-map": "0.84.4", - "nullthrows": "^1.1.1", - "source-map": "^0.5.6", - "vlq": "^1.0.0" - }, - "bin": { - "metro-symbolicate": "src/index.js" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-transform-plugins": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.4.tgz", - "integrity": "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/metro-transform-worker": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.4.tgz", - "integrity": "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/core": "^7.25.2", - "@babel/generator": "^7.29.1", - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "flow-enums-runtime": "^0.0.6", - "metro": "0.84.4", - "metro-babel-transformer": "0.84.4", - "metro-cache": "0.84.4", - "metro-cache-key": "0.84.4", - "metro-minify-terser": "0.84.4", - "metro-source-map": "0.84.4", - "metro-transform-plugins": "0.84.4", - "nullthrows": "^1.1.1" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@react-native/metro-config/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/@react-native/metro-config/node_modules/ob1": { - "version": "0.84.4", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.4.tgz", - "integrity": "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==", - "license": "MIT", - "peer": true, - "dependencies": { - "flow-enums-runtime": "^0.0.6" - }, - "engines": { - "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@react-native/metro-config/node_modules/ws": { - "version": "7.5.11", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", - "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@react-native/normalize-colors": { - "version": "0.81.6", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.6.tgz", - "integrity": "sha512-/OCgUysHIFhfmZxbJAydVc58l2SGIZbWpbQXBrYEYch8YElBbDFQ8IUtyogB7YJJQ8ewHZFj93rQGaECgkvvcw==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.86.3.tgz", + "integrity": "sha512-Cv3CDkprb67GrzuaS9BGbBJC/6G4lIw3nyKOHRKTqTTum4bn37y5+R0Z04L8mcbQN85eEohNrRwb7IOM4j6uvg==", "license": "MIT" }, "node_modules/@react-native/virtualized-lists": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.81.5.tgz", - "integrity": "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.86.3.tgz", + "integrity": "sha512-1j44NEyNn05Ut40vHAmoSWbsIcybFkMAOBTwQt1PrESyfSS+qBoyU1LGIogNva0VIa0rQyEC5PzbA7R4/7Nhyw==", "license": "MIT", "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "@types/react": "^19.1.0", + "@types/react": "^19.2.0", "react": "*", - "react-native": "*" + "react-native": "0.86.3" }, "peerDependenciesMeta": { "@types/react": { @@ -11262,24 +11423,6 @@ } } }, - "node_modules/@react-navigation/bottom-tabs": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-7.15.5.tgz", - "integrity": "sha512-wQHredlCrRmShWQ1vF4HUcLdaiJ8fUgnbaeQH7BJ7MQVQh4mdzab0IOY/4QSmUyNRB350oyu1biTycyQ5FKWMQ==", - "license": "MIT", - "dependencies": { - "@react-navigation/elements": "^2.9.10", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0" - }, - "peerDependencies": { - "@react-navigation/native": "^7.1.33", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" - } - }, "node_modules/@react-navigation/core": { "version": "7.16.1", "resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-7.16.1.tgz", @@ -11299,29 +11442,6 @@ "react": ">= 18.2.0" } }, - "node_modules/@react-navigation/elements": { - "version": "2.9.10", - "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-2.9.10.tgz", - "integrity": "sha512-N8tuBekzTRb0pkMHFJGvmC6Q5OisSbt6gzvw7RHMnp4NDo5auVllT12sWFaTXf8mTduaLKNSrD/NZNaOqThCBg==", - "license": "MIT", - "dependencies": { - "color": "^4.2.3", - "use-latest-callback": "^0.2.4", - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@react-native-masked-view/masked-view": ">= 0.2.0", - "@react-navigation/native": "^7.1.33", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0" - }, - "peerDependenciesMeta": { - "@react-native-masked-view/masked-view": { - "optional": true - } - } - }, "node_modules/@react-navigation/native": { "version": "7.1.33", "resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.33.tgz", @@ -11339,25 +11459,6 @@ "react-native": "*" } }, - "node_modules/@react-navigation/native-stack": { - "version": "7.14.4", - "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-7.14.4.tgz", - "integrity": "sha512-HFEnM5Q7JY3FmmiolD/zvgY+9sxZAyVGPZJoz7BdTvJmi1VHOdplf24YiH45mqeitlGnaOlvNT55rH4abHJ5eA==", - "license": "MIT", - "dependencies": { - "@react-navigation/elements": "^2.9.10", - "color": "^4.2.3", - "sf-symbols-typescript": "^2.1.0", - "warn-once": "^0.1.1" - }, - "peerDependencies": { - "@react-navigation/native": "^7.1.33", - "react": ">= 18.2.0", - "react-native": "*", - "react-native-safe-area-context": ">= 4.0.0", - "react-native-screens": ">= 4.0.0" - } - }, "node_modules/@react-navigation/routers": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-7.5.3.tgz", @@ -11887,32 +11988,6 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, - "node_modules/@shopify/react-native-skia": { - "version": "2.2.12", - "resolved": "https://registry.npmjs.org/@shopify/react-native-skia/-/react-native-skia-2.2.12.tgz", - "integrity": "sha512-P5wZSMPTp00hM0do+awNFtb5aPh5hSpodMGwy7NaxK90AV+SmUu7wZe6NGevzQIwgFa89Epn6xK3j4jKWdQi+A==", - "license": "MIT", - "dependencies": { - "canvaskit-wasm": "0.40.0", - "react-reconciler": "0.31.0" - }, - "bin": { - "setup-skia-web": "scripts/setup-canvaskit.js" - }, - "peerDependencies": { - "react": ">=19.0", - "react-native": ">=0.78", - "react-native-reanimated": ">=3.19.1" - }, - "peerDependenciesMeta": { - "react-native": { - "optional": true - }, - "react-native-reanimated": { - "optional": true - } - } - }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -11959,6 +12034,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -11968,6 +12044,7 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" @@ -12507,6 +12584,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -12520,6 +12598,7 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -12529,6 +12608,7 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -12539,6 +12619,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -12878,6 +12959,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/emscripten": { + "version": "1.41.6", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.6.tgz", + "integrity": "sha512-uN+9i8bFT5CUcZfyIEYDrSueACEyKGbUs5kC/72DGlZZoinh84sJfVV0i8UOJD1asdzkvLPBRrKs41kZ8MdEXg==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -12939,6 +13026,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*" @@ -13183,6 +13271,15 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/react-test-renderer": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-19.3.0.tgz", + "integrity": "sha512-TX4p2D4Z2oigM3SXU7+QyLSUnSR0vR1S1Pfxm/qFL9nHQ3jclgi6ioGoWQmlIr1DeKRVmPJrmNlhgM0JlWlLUg==", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/responselike": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", @@ -13237,6 +13334,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, "license": "MIT" }, "node_modules/@types/tough-cookie": { @@ -13306,288 +13404,6 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "license": "MIT" }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", - "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/type-utils": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", - "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", - "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.1", - "@typescript-eslint/types": "^8.56.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", - "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", - "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", - "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1", - "@typescript-eslint/utils": "8.56.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", - "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", - "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.56.1", - "@typescript-eslint/tsconfig-utils": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/visitor-keys": "8.56.1", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", - "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.1", - "@typescript-eslint/types": "8.56.1", - "@typescript-eslint/typescript-estree": "8.56.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", - "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.1", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@typescript/native-preview": { "version": "7.0.0-dev.20260423.1", "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260423.1.tgz", @@ -14516,6 +14332,18 @@ "node": ">= 6.0.0" } }, + "node_modules/agent-cli-detector": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/agent-cli-detector/-/agent-cli-detector-0.1.7.tgz", + "integrity": "sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==", + "license": "MIT", + "bin": { + "agent-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, "node_modules/ai": { "version": "5.0.78", "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.78.tgz", @@ -14538,6 +14366,7 @@ "version": "8.11.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -14645,12 +14474,14 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -14664,6 +14495,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -15181,19 +15013,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/assert": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", - "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "is-nan": "^1.3.2", - "object-is": "^1.1.5", - "object.assign": "^4.1.4", - "util": "^0.12.5" - } - }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -15252,12 +15071,6 @@ "node": ">= 0.4" } }, - "node_modules/async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "license": "MIT" - }, "node_modules/async-sema": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", @@ -15295,6 +15108,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -15355,6 +15169,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", @@ -15376,6 +15191,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -15395,6 +15211,7 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", @@ -15411,6 +15228,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", @@ -15489,6 +15307,7 @@ "version": "0.29.1", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.29.1.tgz", "integrity": "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA==", + "dev": true, "license": "MIT", "dependencies": { "hermes-parser": "0.29.1" @@ -15507,6 +15326,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -15533,6 +15353,7 @@ "version": "54.0.10", "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-54.0.10.tgz", "integrity": "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -15576,6 +15397,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", @@ -15608,8 +15430,18 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, + "node_modules/barcode-detector": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.2.2.tgz", + "integrity": "sha512-/4QOrrNrCRmDSBWiiP4aC72dnkuXUEdcFRidHgbPRXUpy82XcCMvJssI6fEs6JT42LS7DvBVZO70qasJbYKyrA==", + "license": "MIT", + "dependencies": { + "zxing-wasm": "3.1.3" + } + }, "node_modules/bare-events": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", @@ -15670,6 +15502,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", "integrity": "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==", + "dev": true, "license": "MIT", "dependencies": { "open": "^8.0.4" @@ -15682,6 +15515,7 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", @@ -15825,6 +15659,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -16181,6 +16016,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -16285,15 +16121,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/canvaskit-wasm": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/canvaskit-wasm/-/canvaskit-wasm-0.40.0.tgz", - "integrity": "sha512-Od2o+ZmoEw9PBdN/yCGvzfu0WVqlufBPEWNG452wY7E9aT8RBE+ChpZF526doOlg7zumO4iCS+RAeht4P0Gbpw==", - "license": "BSD-3-Clause", - "dependencies": { - "@webgpu/types": "0.1.21" - } - }, "node_modules/cardinal": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", @@ -16478,17 +16305,16 @@ } }, "node_modules/chromium-edge-launcher": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", - "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", + "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", "license": "Apache-2.0", "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "mkdirp": "^1.0.4" } }, "node_modules/chromium-pickle-js": { @@ -16762,14 +16588,15 @@ } }, "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz", + "integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==", "license": "MIT", "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", + "destroy": "1.2.0", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", @@ -16777,6 +16604,10 @@ }, "engines": { "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/compression/node_modules/debug": { @@ -16807,6 +16638,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/concurrently": { @@ -17926,15 +17758,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -18004,6 +17827,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -18021,6 +17845,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -18030,6 +17855,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -18269,6 +18095,12 @@ "license": "MIT", "optional": true }, + "node_modules/dnssd-advertise": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/dnssd-advertise/-/dnssd-advertise-1.1.6.tgz", + "integrity": "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==", + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -18400,6 +18232,7 @@ "version": "11.0.7", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "dotenv": "^16.4.5" @@ -18415,6 +18248,7 @@ "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -18955,15 +18789,6 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/env-editor": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-0.4.2.tgz", - "integrity": "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/env-paths": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", @@ -19406,39 +19231,6 @@ "eslint": ">=6.0.0" } }, - "node_modules/eslint-config-expo": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-expo/-/eslint-config-expo-10.0.0.tgz", - "integrity": "sha512-/XC/DvniUWTzU7Ypb/cLDhDD4DXqEio4lug1ObD/oQ9Hcx3OVOR8Mkp4u6U4iGoZSJyIQmIk3WVHe/P1NYUXKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "^8.18.2", - "@typescript-eslint/parser": "^8.18.2", - "eslint-import-resolver-typescript": "^3.6.3", - "eslint-plugin-expo": "^1.0.0", - "eslint-plugin-import": "^2.30.0", - "eslint-plugin-react": "^7.37.3", - "eslint-plugin-react-hooks": "^5.1.0", - "globals": "^16.0.0" - }, - "peerDependencies": { - "eslint": ">=8.10" - } - }, - "node_modules/eslint-config-expo/node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -19566,24 +19358,6 @@ "eslint": ">=8" } }, - "node_modules/eslint-plugin-expo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-expo/-/eslint-plugin-expo-1.0.0.tgz", - "integrity": "sha512-qLtunR+cNFtC+jwYCBia5c/PJurMjSLMOV78KrEOyQK02ohZapU4dCFFnS2hfrJuw0zxfsjVkjqg3QBqi933QA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "^8.29.1", - "@typescript-eslint/utils": "^8.29.1", - "eslint": "^9.24.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "eslint": ">=8.10" - } - }, "node_modules/eslint-plugin-import": { "version": "2.32.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", @@ -19831,19 +19605,6 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, - "node_modules/eslint-plugin-react-hooks": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -20041,6 +19802,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -20217,32 +19979,34 @@ } }, "node_modules/expo": { - "version": "54.0.33", - "resolved": "https://registry.npmjs.org/expo/-/expo-54.0.33.tgz", - "integrity": "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw==", + "version": "57.0.30", + "resolved": "https://registry.npmjs.org/expo/-/expo-57.0.30.tgz", + "integrity": "sha512-dpNWbsqiAHkgInOBClv5PxKCSMAly1n0oBVoIjS/yv8LQtRgDqSkWAnJq16cExndKrgONxdItY+O3J8u6MNYlw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "54.0.23", - "@expo/config": "~12.0.13", - "@expo/config-plugins": "~54.0.4", - "@expo/devtools": "0.1.8", - "@expo/fingerprint": "0.15.4", - "@expo/metro": "~54.2.0", - "@expo/metro-config": "54.0.14", - "@expo/vector-icons": "^15.0.3", + "@expo/cli": "^57.0.31", + "@expo/config": "~57.0.10", + "@expo/config-plugins": "~57.0.10", + "@expo/devtools": "~57.0.1", + "@expo/dom-webview": "~57.0.1", + "@expo/fingerprint": "^0.20.14", + "@expo/local-build-cache-provider": "^57.0.9", + "@expo/log-box": "^57.0.4", + "@expo/metro": "~56.0.2", + "@expo/metro-config": "~57.0.13", "@ungap/structured-clone": "^1.3.0", - "babel-preset-expo": "~54.0.10", - "expo-asset": "~12.0.12", - "expo-constants": "~18.0.13", - "expo-file-system": "~19.0.21", - "expo-font": "~14.0.11", - "expo-keep-awake": "~15.0.8", - "expo-modules-autolinking": "3.0.24", - "expo-modules-core": "3.0.29", + "babel-preset-expo": "~57.0.16", + "expo-asset": "~57.0.20", + "expo-constants": "~57.0.22", + "expo-file-system": "~57.0.7", + "expo-font": "~57.0.4", + "expo-keep-awake": "~57.0.2", + "expo-modules-autolinking": "~57.0.16", + "expo-modules-core": "~57.0.23", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", - "whatwg-url-without-unicode": "8.0.0-3" + "whatwg-url-minimum": "^0.1.2" }, "bin": { "expo": "bin/cli", @@ -20253,7 +20017,9 @@ "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", + "react-dom": "*", "react-native": "*", + "react-native-web": "*", "react-native-webview": "*" }, "peerDependenciesMeta": { @@ -20263,28 +20029,25 @@ "@expo/metro-runtime": { "optional": true }, + "react-dom": { + "optional": true + }, + "react-native-web": { + "optional": true + }, "react-native-webview": { "optional": true } } }, - "node_modules/expo-application": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz", - "integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, "node_modules/expo-asset": { - "version": "12.0.12", - "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.12.tgz", - "integrity": "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ==", + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-57.0.20.tgz", + "integrity": "sha512-xm1p3Squ/dCzipISO1TE5+kDsIFEUc6DxEtRe2rRgPMDLPi6AumLlrNorFxetiP6zrvxK23xzVlNng/g7o/+aA==", "license": "MIT", "dependencies": { - "@expo/image-utils": "^0.8.8", - "expo-constants": "~18.0.12" + "@expo/image-utils": "^0.11.6", + "expo-constants": "~57.0.22" }, "peerDependencies": { "expo": "*", @@ -20293,20 +20056,32 @@ } }, "node_modules/expo-asset/node_modules/@expo/image-utils": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.12.tgz", - "integrity": "sha512-3KguH7kyKqq7pNwLb9j6BBdD/bjmNwXZG/HPWT6GWIXbwrvAJt2JNyYTP5agWJ8jbbuys1yuCzmkX+TU6rmI7A==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.11.6.tgz", + "integrity": "sha512-rmMpn7QGp6pUGRCQ3vvB9RP/vqq2q/PpToRh4dL/FbhSZOLZ1YTotpuLHf71FGOEfgKil/4PCd3hkWe/CCeiEg==", "license": "MIT", "dependencies": { - "@expo/spawn-async": "^1.7.2", + "@expo/require-utils": "^57.0.6", + "@expo/spawn-async": "^1.8.0", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", - "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, + "node_modules/expo-asset/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/expo-asset/node_modules/getenv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", @@ -20316,220 +20091,42 @@ "node": ">=6" } }, - "node_modules/expo-audio": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/expo-audio/-/expo-audio-1.0.16.tgz", - "integrity": "sha512-j7otyjtO+8PVbemoCoRBr2Em0Kv9to3bfz5UpI5tDVVb5gD1dkn7sjv6/W6tWNqx14WLR1Wijh/ACecVv1Py+g==", + "node_modules/expo-clipboard": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-57.0.2.tgz", + "integrity": "sha512-VB4Au8X/RbvJKUtJk+87vdtveWSNEa5RzY3ooeO6VNF7Rd49RbQXZOu3/TfEW9p7mU8TCfyTvjyCiAUwSoSJ4w==", "license": "MIT", - "peerDependencies": { - "expo": "*", - "expo-asset": "*", - "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-build-properties": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-1.0.10.tgz", - "integrity": "sha512-mFCZbrbrv0AP5RB151tAoRzwRJelqM7bCJzCkxpu+owOyH+p/rFC/q7H5q8B9EpVWj8etaIuszR+gKwohpmu1Q==", - "license": "MIT", - "dependencies": { - "ajv": "^8.11.0", - "semver": "^7.6.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-camera": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-17.0.10.tgz", - "integrity": "sha512-w1RBw83mAGVk4BPPwNrCZyFop0VLiVSRE3c2V9onWbdFwonpRhzmB4drygG8YOUTl1H3wQvALJHyMPTbgsK1Jg==", - "license": "MIT", - "dependencies": { - "invariant": "^2.2.4" - }, "peerDependencies": { "expo": "*", "react": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } + "react-native": "*" } }, "node_modules/expo-constants": { - "version": "18.0.13", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz", - "integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==", + "version": "57.0.22", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-57.0.22.tgz", + "integrity": "sha512-+mBjnzMWMKIrQa7BP7LTDRC0W7cI+q12/sZns4HzVQJGzgGoAdRJSTEKiObxIw/3EswKXlESkRob8upiL95Q4A==", "license": "MIT", "dependencies": { - "@expo/config": "~12.0.13", - "@expo/env": "~2.0.8" + "@expo/env": "~2.4.3" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, - "node_modules/expo-constants/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/expo-constants/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" - } - }, - "node_modules/expo-constants/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.4", - "slash": "^3.0.0", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/expo-constants/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", - "license": "MIT" - }, "node_modules/expo-constants/node_modules/@expo/env": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.0.11.tgz", - "integrity": "sha512-xV+ps6YCW7XIPVUwFVCRN2nox09dnRwy8uIjwHWTODu0zFw4kp4omnVkl0OOjuu2XOe7tdgAHxikrkJt9xB/7Q==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.4.3.tgz", + "integrity": "sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==", "license": "MIT", "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", - "dotenv": "~16.4.5", - "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" - } - }, - "node_modules/expo-constants/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/expo-constants/node_modules/@expo/json-file/node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/expo-constants/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/expo-constants/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/expo-constants/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-constants/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-constants/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/expo-constants/node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" + "node": ">=20.12.0" } }, "node_modules/expo-constants/node_modules/getenv": { @@ -20541,179 +20138,10 @@ "node": ">=6" } }, - "node_modules/expo-constants/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-constants/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/expo-constants/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-constants/node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-constants/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo-constants/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/expo-constants/node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/expo-crypto": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-15.0.8.tgz", - "integrity": "sha512-aF7A914TB66WIlTJvl5J6/itejfY78O7dq3ibvFltL9vnTALJ/7LYHvLT4fwmx9yUNS6ekLBtDGWivFWnj2Fcw==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-dev-client": { - "version": "6.0.20", - "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-6.0.20.tgz", - "integrity": "sha512-5XjoVlj1OxakNxy55j/AUaGPrDOlQlB6XdHLLWAw61w5ffSpUDHDnuZzKzs9xY1eIaogOqTOQaAzZ2ddBkdXLA==", - "license": "MIT", - "dependencies": { - "expo-dev-launcher": "6.0.20", - "expo-dev-menu": "7.0.18", - "expo-dev-menu-interface": "2.0.0", - "expo-manifests": "~1.0.10", - "expo-updates-interface": "~2.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-dev-launcher": { - "version": "6.0.20", - "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-6.0.20.tgz", - "integrity": "sha512-a04zHEeT9sB0L5EB38fz7sNnUKJ2Ar1pXpcyl60Ki8bXPNCs9rjY7NuYrDkP/irM8+1DklMBqHpyHiLyJ/R+EA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.11.0", - "expo-dev-menu": "7.0.18", - "expo-manifests": "~1.0.10" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-dev-menu": { - "version": "7.0.18", - "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-7.0.18.tgz", - "integrity": "sha512-4kTdlHrnZCAWCT6tZRQHSSjZ7vECFisL4T+nsG/GJDo/jcHNaOVGV5qPV9wzlTxyMk3YOPggRw4+g7Ownrg5eA==", - "license": "MIT", - "dependencies": { - "expo-dev-menu-interface": "2.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-dev-menu-interface": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/expo-dev-menu-interface/-/expo-dev-menu-interface-2.0.0.tgz", - "integrity": "sha512-BvAMPt6x+vyXpThsyjjOYyjwfjREV4OOpQkZ0tNl+nGpsPfcY9mc6DRACoWnH9KpLzyIt3BOgh3cuy/h/OxQjw==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-document-picker": { - "version": "14.0.8", - "resolved": "https://registry.npmjs.org/expo-document-picker/-/expo-document-picker-14.0.8.tgz", - "integrity": "sha512-3tyQKpPqWWFlI8p9RiMX1+T1Zge5mEKeBuXWp1h8PEItFMUDSiOJbQ112sfdC6Hxt8wSxreV9bCRl/NgBdt+fA==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, "node_modules/expo-file-system": { - "version": "19.0.21", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.21.tgz", - "integrity": "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg==", + "version": "57.0.7", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-57.0.7.tgz", + "integrity": "sha512-1vkZRadOsIputFDBcclqBa1pO3iXOO6iIsdqJipQWw4V5TSnWgmRTuOF7ro8IzrVue+PHbum++KCG3Tawem4cg==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -20721,9 +20149,9 @@ } }, "node_modules/expo-font": { - "version": "14.0.11", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-14.0.11.tgz", - "integrity": "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg==", + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.4.tgz", + "integrity": "sha512-7WOMC2oA6xCfOm8bbofqWn2bIqyWFm7YLEnpc/gA1MJH0Ll0TfT/3+CqRkoW2eNRWMS8sxrz5WukUmSvmNquHA==", "license": "MIT", "dependencies": { "fontfaceobserver": "^2.1.0" @@ -20734,6 +20162,17 @@ "react-native": "*" } }, + "node_modules/expo-glass-effect": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-glass-effect/-/expo-glass-effect-57.0.4.tgz", + "integrity": "sha512-/AG2Kljbqfgxu+GchI2YFIbxiF9cPsIpCy4iNDzlRiZk9rvR6BwRfB6gfQVu3V2ExaoGf2h5IsEnqVI5MYNBAg==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-gradle-jvmargs": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/expo-gradle-jvmargs/-/expo-gradle-jvmargs-1.1.2.tgz", @@ -20744,75 +20183,10 @@ "@expo/config-plugins": "*" } }, - "node_modules/expo-haptics": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-15.0.8.tgz", - "integrity": "sha512-lftutojy8Qs8zaDzzjwM3gKHFZ8bOOEZDCkmh2Ddpe95Ra6kt2izeOfOfKuP/QEh0MZ1j9TfqippyHdRd1ZM9g==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-image": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-3.0.11.tgz", - "integrity": "sha512-4TudfUCLgYgENv+f48omnU8tjS2S0Pd9EaON5/s1ZUBRwZ7K8acEr4NfvLPSaeXvxW24iLAiyQ7sV7BXQH3RoA==", - "license": "MIT", - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } - } - }, - "node_modules/expo-image-loader": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-6.0.0.tgz", - "integrity": "sha512-nKs/xnOGw6ACb4g26xceBD57FKLFkSwEUTDXEDF3Gtcu3MqF3ZIYd3YM+sSb1/z9AKV1dYT7rMSGVNgsveXLIQ==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-image-manipulator": { - "version": "14.0.8", - "resolved": "https://registry.npmjs.org/expo-image-manipulator/-/expo-image-manipulator-14.0.8.tgz", - "integrity": "sha512-sXsXjm7rIxLWZe0j2A41J/Ph53PpFJRdyzJ3EQ/qetxLUvS2m3K1sP5xy37px43qCf0l79N/i6XgFgenFV36/Q==", - "license": "MIT", - "dependencies": { - "expo-image-loader": "~6.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-image-picker": { - "version": "17.0.10", - "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-17.0.10.tgz", - "integrity": "sha512-a2xrowp2trmvXyUWgX3O6Q2rZaa2C59AqivKI7+bm+wLvMfTEbZgldLX4rEJJhM8xtmEDTNU+lzjtObwzBRGaw==", - "license": "MIT", - "dependencies": { - "expo-image-loader": "~6.0.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-json-utils": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-0.15.0.tgz", - "integrity": "sha512-duRT6oGl80IDzH2LD2yEFWNwGIC2WkozsB6HF3cDYNoNNdUvFk6uN3YiwsTsqVM/D0z6LEAQ01/SlYvN+Fw0JQ==", - "license": "MIT" - }, "node_modules/expo-keep-awake": { - "version": "15.0.8", - "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-15.0.8.tgz", - "integrity": "sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ==", + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.2.tgz", + "integrity": "sha512-GqgH746wtJImmsbyHmCQoi7cOslKuWQBbJHXr53S35Bpf5UvxCAztvnitUEd7D0QvFN2rvkOhylbZpgZZfBLlQ==", "license": "MIT", "peerDependencies": { "expo": "*", @@ -20820,12 +20194,12 @@ } }, "node_modules/expo-linking": { - "version": "8.0.11", - "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.11.tgz", - "integrity": "sha512-+VSaNL5om3kOp/SSKO5qe6cFgfSIWnnQDSbA7XLs3ECkYzXRquk5unxNS3pg7eK5kNUmQ4kgLI7MhTggAEUBLA==", + "version": "57.0.13", + "resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-57.0.13.tgz", + "integrity": "sha512-1cjN7Ely0FZqlZItfPYjl6jjrCFLRevrIE/H5XhA6tgDm9uhTaSyJQXyftgt2FvJZ7liheDft7WMnPB9Uktx+A==", "license": "MIT", "dependencies": { - "expo-constants": "~18.0.12", + "expo-constants": "~57.0.22", "invariant": "^2.2.4" }, "peerDependencies": { @@ -20833,394 +20207,127 @@ "react-native": "*" } }, - "node_modules/expo-localization": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-17.0.9.tgz", - "integrity": "sha512-k5eYHr7iLMob3M8cHH6bgDrDRmqnZG8xKGLhpx8ST+LsFXmSgYpJ/t0VwWm0gz64C/K669XhObdG3D6QwCGqhw==", - "license": "MIT", - "dependencies": { - "rtl-detect": "^1.0.2" - }, - "peerDependencies": { - "expo": "*", - "react": "*" - } - }, - "node_modules/expo-manifests": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-1.0.10.tgz", - "integrity": "sha512-oxDUnURPcL4ZsOBY6X1DGWGuoZgVAFzp6PISWV7lPP2J0r8u1/ucuChBgpK7u1eLGFp6sDIPwXyEUCkI386XSQ==", - "license": "MIT", - "dependencies": { - "@expo/config": "~12.0.11", - "expo-json-utils": "~0.15.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-manifests/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/expo-manifests/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" - } - }, - "node_modules/expo-manifests/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.4", - "slash": "^3.0.0", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/expo-manifests/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", - "license": "MIT" - }, - "node_modules/expo-manifests/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/expo-manifests/node_modules/@expo/json-file/node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/expo-manifests/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/expo-manifests/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/expo-manifests/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-manifests/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-manifests/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/expo-manifests/node_modules/getenv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", - "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/expo-manifests/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-manifests/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/expo-manifests/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-manifests/node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-manifests/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo-manifests/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/expo-manifests/node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, "node_modules/expo-modules-autolinking": { - "version": "3.0.24", - "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-3.0.24.tgz", - "integrity": "sha512-TP+6HTwhL7orDvsz2VzauyQlXJcAWyU3ANsZ7JGL4DQu8XaZv/A41ZchbtAYLfozNA2Ya1Hzmhx65hXryBMjaQ==", + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-57.0.16.tgz", + "integrity": "sha512-OJh6rMMIIZ/dfwOk2FufJjjsUSw5Boy1Y5Tl+zbBmua/FcD03eEg097dkYIf3iBHVkQ6q9eR08qT88qxvnelow==", "license": "MIT", "dependencies": { - "@expo/spawn-async": "^1.7.2", + "@expo/require-utils": "^57.0.6", + "@expo/spawn-async": "^1.8.0", "chalk": "^4.1.0", - "commander": "^7.2.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0" + "commander": "^7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, - "node_modules/expo-modules-core": { - "version": "3.0.29", - "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-3.0.29.tgz", - "integrity": "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q==", + "node_modules/expo-modules-autolinking/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", "license": "MIT", "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/expo-modules-core": { + "version": "57.0.23", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-57.0.23.tgz", + "integrity": "sha512-vZQoSlhqU6me5K4KCl42yXB0x3zqAiG2FAjzHmbuez77CslJJQ+82cmJoHC3tN5X8o/KxRArJejKNQIeciyoXA==", + "license": "MIT", + "dependencies": { + "@expo/expo-modules-macros-plugin": "0.6.1", + "expo-modules-jsi": "~57.1.2", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", - "react-native": "*" - } - }, - "node_modules/expo-notifications": { - "version": "0.32.16", - "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.16.tgz", - "integrity": "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw==", - "license": "MIT", - "dependencies": { - "@expo/image-utils": "^0.8.8", - "@ide/backoff": "^1.0.0", - "abort-controller": "^3.0.0", - "assert": "^2.0.0", - "badgin": "^1.1.5", - "expo-application": "~7.0.8", - "expo-constants": "~18.0.13" + "react-native": "*", + "react-native-worklets": "^0.7.4 || ^0.8.0 || ^0.9.0 || ^0.10.0" }, + "peerDependenciesMeta": { + "react-native-worklets": { + "optional": true + } + } + }, + "node_modules/expo-modules-jsi": { + "version": "57.1.2", + "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-57.1.2.tgz", + "integrity": "sha512-DYhBwO0fqcKIUma4jF16zRDP/m6ZbawEZbo4eX3gdekREIFqrrz8HKWXydgNUqOyOQcUkdrkZatxi2I9+V6E8g==", + "license": "MIT", "peerDependencies": { - "expo": "*", - "react": "*", "react-native": "*" } }, - "node_modules/expo-notifications/node_modules/@expo/image-utils": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.12.tgz", - "integrity": "sha512-3KguH7kyKqq7pNwLb9j6BBdD/bjmNwXZG/HPWT6GWIXbwrvAJt2JNyYTP5agWJ8jbbuys1yuCzmkX+TU6rmI7A==", + "node_modules/expo-modules-macros": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/expo-modules-macros/-/expo-modules-macros-0.20.0.tgz", + "integrity": "sha512-Ekgb5c9LQPM9CPnmDZdeWcOa1eBbCDUGrgdN5lIFNH2GWDUf9doeAOK7IqQOOVviamy37eIp5FW+N1zyrIwzoA==", + "dev": true, "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.7.2", - "chalk": "^4.0.0", - "getenv": "^2.0.0", - "jimp-compact": "0.16.1", - "parse-png": "^2.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - } - }, - "node_modules/expo-notifications/node_modules/getenv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", - "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", - "license": "MIT", - "engines": { - "node": ">=6" + "peer": true, + "optionalDependencies": { + "@expo/modules-macros-win32-arm64": "0.20.0", + "@expo/modules-macros-win32-x64": "0.20.0" } }, "node_modules/expo-router": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.23.tgz", - "integrity": "sha512-qCxVAiCrCyu0npky6azEZ6dJDMt77OmCzEbpF6RbUTlfkaCA417LvY14SBkk0xyGruSxy/7pvJOI6tuThaUVCA==", + "version": "57.0.28", + "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-57.0.28.tgz", + "integrity": "sha512-KrW7dGtZ1A9ocpt/Gq1RKczfoAkJ+2LrxweVcEq/FZcJ+eFsaKC9f60ER3uzWJ9n9mb+dbeSPewYOMzG6KMK2Q==", "license": "MIT", "dependencies": { - "@expo/metro-runtime": "^6.1.2", - "@expo/schema-utils": "^0.1.8", - "@radix-ui/react-slot": "1.2.0", + "@expo/log-box": "^57.0.4", + "@expo/metro-runtime": "^57.0.17", + "@expo/schema-utils": "^57.0.2", + "@expo/ui": "^57.0.25", + "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", - "@react-navigation/bottom-tabs": "^7.4.0", - "@react-navigation/native": "^7.1.8", - "@react-navigation/native-stack": "^7.3.16", + "@react-native-masked-view/masked-view": "^0.3.2", "client-only": "^0.0.1", + "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", - "expo-server": "^1.0.5", + "expo-glass-effect": "^57.0.4", + "expo-server": "^57.0.3", + "expo-symbols": "^57.0.3", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", - "nanoid": "^3.3.8", + "nanoid": "^3.3.18", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", - "react-native-is-edge-to-edge": "^1.1.6", - "semver": "~7.6.3", + "react-is": "^19.1.0", + "react-native-drawer-layout": "^4.2.2", + "react-native-screens": "^4.26.0", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", - "use-latest-callback": "^0.2.1", + "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { - "@expo/metro-runtime": "^6.1.2", - "@react-navigation/drawer": "^7.5.0", - "@testing-library/react-native": ">= 12.0.0", + "@expo/log-box": "^57.0.4", + "@expo/metro-runtime": "^57.0.17", + "@testing-library/react-native": ">= 13.2.0", "expo": "*", - "expo-constants": "^18.0.13", - "expo-linking": "^8.0.11", + "expo-constants": "^57.0.22", + "expo-linking": "^57.0.13", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", - "react-native-screens": "*", + "react-native-screens": "^4.26.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "peerDependenciesMeta": { - "@react-navigation/drawer": { - "optional": true - }, "@testing-library/react-native": { "optional": true }, @@ -21241,465 +20348,241 @@ } } }, - "node_modules/expo-router/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/expo-server": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-1.0.5.tgz", - "integrity": "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA==", + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-57.0.3.tgz", + "integrity": "sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==", "license": "MIT", "engines": { "node": ">=20.16.0" } }, - "node_modules/expo-sharing": { - "version": "14.0.8", - "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-14.0.8.tgz", - "integrity": "sha512-A1pPr2iBrxypFDCWVAESk532HK+db7MFXbvO2sCV9ienaFXAk7lIBm6bkqgE6vzRd9O3RGdEGzYx80cYlc089Q==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-splash-screen": { - "version": "31.0.13", - "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-31.0.13.tgz", - "integrity": "sha512-1epJLC1cDlwwj089R2h8cxaU5uk4ONVAC+vzGiTZH4YARQhL4Stlz1MbR6yAS173GMosvkE6CAeihR7oIbCkDA==", + "node_modules/expo-symbols": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-57.0.3.tgz", + "integrity": "sha512-uuK5yHLVR7kExUCrO/ItBvp/kp1maQ9Nkb6KvNy5ZUQnN0NMKwuhJ4GvbfS9N3ACmvCjTT4gKvg4yH5UuKIYNA==", "license": "MIT", "dependencies": { - "@expo/prebuild-config": "^54.0.8" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", - "deepmerge": "^4.3.1", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", - "resolve-workspace-root": "^2.0.0", - "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", - "license": "MIT", - "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", - "@expo/sdk-runtime-versions": "^1.0.0", - "chalk": "^4.1.2", - "debug": "^4.3.5", - "getenv": "^2.0.0", - "glob": "^13.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.5.4", - "slash": "^3.0.0", - "slugify": "^1.6.6", - "xcode": "^3.0.1", - "xml2js": "0.6.0" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", - "license": "MIT" - }, - "node_modules/expo-splash-screen/node_modules/@expo/config/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/image-utils": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.8.12.tgz", - "integrity": "sha512-3KguH7kyKqq7pNwLb9j6BBdD/bjmNwXZG/HPWT6GWIXbwrvAJt2JNyYTP5agWJ8jbbuys1yuCzmkX+TU6rmI7A==", - "license": "MIT", - "dependencies": { - "@expo/spawn-async": "^1.7.2", - "chalk": "^4.0.0", - "getenv": "^2.0.0", - "jimp-compact": "0.16.1", - "parse-png": "^2.1.0", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.20.0", - "json5": "^2.2.3" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", - "xmlbuilder": "^15.1.1" - } - }, - "node_modules/expo-splash-screen/node_modules/@expo/prebuild-config": { - "version": "54.0.8", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-54.0.8.tgz", - "integrity": "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg==", - "license": "MIT", - "dependencies": { - "@expo/config": "~12.0.13", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/image-utils": "^0.8.8", - "@expo/json-file": "^10.0.8", - "@react-native/normalize-colors": "0.81.5", - "debug": "^4.3.1", - "resolve-from": "^5.0.0", - "semver": "^7.6.0", - "xml2js": "0.6.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-splash-screen/node_modules/@react-native/normalize-colors": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", - "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", - "license": "MIT" - }, - "node_modules/expo-splash-screen/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/expo-splash-screen/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-splash-screen/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo-splash-screen/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/expo-splash-screen/node_modules/getenv": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", - "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/expo-splash-screen/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-splash-screen/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/expo-splash-screen/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-splash-screen/node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/expo-splash-screen/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo-splash-screen/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/expo-splash-screen/node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/expo-sqlite": { - "version": "16.0.10", - "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-16.0.10.tgz", - "integrity": "sha512-tUOKxE9TpfneRG3eOfbNfhN9236SJ7IiUnP8gCqU7umd9DtgDGB/5PhYVVfl+U7KskgolgNoB9v9OZ9iwXN8Eg==", - "license": "MIT", - "dependencies": { - "await-lock": "^2.2.2" + "@expo-google-fonts/material-symbols": "^0.4.1", + "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", + "expo-font": "*", "react": "*", "react-native": "*" } }, - "node_modules/expo-system-ui": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-6.0.9.tgz", - "integrity": "sha512-eQTYGzw1V4RYiYHL9xDLYID3Wsec2aZS+ypEssmF64D38aDrqbDgz1a2MSlHLQp2jHXSs3FvojhZ9FVela1Zcg==", - "license": "MIT", - "dependencies": { - "@react-native/normalize-colors": "0.81.5", - "debug": "^4.3.2" - }, - "peerDependencies": { - "expo": "*", - "react-native": "*", - "react-native-web": "*" - }, - "peerDependenciesMeta": { - "react-native-web": { - "optional": true - } - } - }, - "node_modules/expo-system-ui/node_modules/@react-native/normalize-colors": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", - "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", - "license": "MIT" - }, - "node_modules/expo-updates-interface": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-2.0.0.tgz", - "integrity": "sha512-pTzAIufEZdVPKql6iMi5ylVSPqV1qbEopz9G6TSECQmnNde2nwq42PxdFBaUEd8IZJ/fdJLQnOT3m6+XJ5s7jg==", - "license": "MIT", - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo/node_modules/@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, "node_modules/expo/node_modules/@expo/config": { - "version": "12.0.13", - "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", - "integrity": "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-57.0.10.tgz", + "integrity": "sha512-YpexTqLWEXdbbXgHh7Zhpq+qA5diuvO46lb7TiY81JwqKLAl9zK31APY1D7jUFlDX56owje5RtK0o5bMmGIMUg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~54.0.4", - "@expo/config-types": "^54.0.10", - "@expo/json-file": "^10.0.8", + "@expo/config-plugins": "~57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "^11.0.1", + "@expo/require-utils": "^57.0.6", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", - "require-from-string": "^2.0.2", - "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", - "slugify": "^1.3.4", - "sucrase": "~3.35.1" + "slugify": "^1.3.4" } }, "node_modules/expo/node_modules/@expo/config-plugins": { - "version": "54.0.4", - "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-54.0.4.tgz", - "integrity": "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q==", + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", "license": "MIT", "dependencies": { - "@expo/config-types": "^54.0.10", - "@expo/json-file": "~10.0.8", - "@expo/plist": "^0.4.8", + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", - "resolve-from": "^5.0.0", "semver": "^7.5.4", - "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, - "node_modules/expo/node_modules/@expo/config-types": { - "version": "54.0.10", - "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-54.0.10.tgz", - "integrity": "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA==", - "license": "MIT" - }, - "node_modules/expo/node_modules/@expo/json-file": { - "version": "10.0.12", - "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.0.12.tgz", - "integrity": "sha512-inbDycp1rMAelAofg7h/mMzIe+Owx6F7pur3XdQ3EPTy00tme+4P6FWgHKUcjN8dBSrnbRNpSyh5/shzHyVCyQ==", + "node_modules/expo/node_modules/@expo/config-plugins/node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.20.0", "json5": "^2.2.3" } }, - "node_modules/expo/node_modules/@expo/json-file/node_modules/@babel/code-frame": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", - "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "node_modules/expo/node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, + "node_modules/expo/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" } }, "node_modules/expo/node_modules/@expo/plist": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.8.tgz", - "integrity": "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", "license": "MIT", "dependencies": { "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.2.3", + "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, + "node_modules/expo/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.86.3.tgz", + "integrity": "sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.86.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/expo/node_modules/@react-native/codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", + "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, "node_modules/expo/node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", "license": "MIT", "engines": { "node": ">=10.0.0" } }, + "node_modules/expo/node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.1.tgz", + "integrity": "sha512-ycduwJbvdvIMmVvlAZqGggS+pm5Eu4Bk9pcV9Sm2Z4PJNRVsKkv0g7vHj+LeuC1gHTeF67sJXFOq61IlqCa2hA==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.1" + } + }, + "node_modules/expo/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "license": "MIT" + }, + "node_modules/expo/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "node_modules/expo/node_modules/babel-preset-expo": { + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.16.tgz", + "integrity": "sha512-hGsVNbgxYchVyvBiFAVf+uHVMVIGObiWzAsnv8GsM/ZZRnrhGJLD8x/BLtNNycEYSIb23wPPlSqTGiw0iwwJvQ==", + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^57.0.26", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, "node_modules/expo/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -21710,24 +20593,15 @@ } }, "node_modules/expo/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/expo/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "license": "MIT", - "engines": { - "node": ">= 6" + "node": "20 || >=22" } }, "node_modules/expo/node_modules/getenv": { @@ -21756,22 +20630,37 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/expo/node_modules/hermes-estree": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", + "license": "MIT" + }, + "node_modules/expo/node_modules/hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, "node_modules/expo/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/expo/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -21805,37 +20694,6 @@ "node": ">=0.10.0" } }, - "node_modules/expo/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/expo/node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/expo/node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -22050,6 +20908,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -22097,6 +20956,18 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", + "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", + "license": "(MIT OR Apache-2.0)", + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -22163,6 +21034,12 @@ } } }, + "node_modules/fetch-nodeshim": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/fetch-nodeshim/-/fetch-nodeshim-0.4.10.tgz", + "integrity": "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w==", + "license": "MIT" + }, "node_modules/fetch-retry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-4.1.1.tgz", @@ -22377,6 +21254,31 @@ "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", "license": "MIT" }, + "node_modules/flow-estree": { + "version": "0.331.0", + "resolved": "https://registry.npmjs.org/flow-estree/-/flow-estree-0.331.0.tgz", + "integrity": "sha512-FVLYkSL/ITb/QXBEQvNWPjPooRGswuUtGOwrH+puSlMDneNkxy640+FZsk/TfKL+b7Wbw/Fg9FTUv2bMQDpj2w==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/flow-parser": { + "version": "0.331.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.331.0.tgz", + "integrity": "sha512-vEZcHIlnKeN8JSVtYFczj8sWJfHIJOkz+YG00O/oul/Bete+t1ZhTi+O6JRRLFYvGW+yJkZ0YgL16iStnbkUqQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-estree": "0.331.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -22408,6 +21310,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -22505,15 +21408,6 @@ } } }, - "node_modules/freeport-async": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/freeport-async/-/freeport-async-2.0.0.tgz", - "integrity": "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -22574,6 +21468,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -22634,6 +21529,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -22694,6 +21590,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -23041,7 +21938,7 @@ "version": "16.8.1", "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" @@ -23130,6 +22027,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -23170,6 +22068,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -23369,16 +22268,24 @@ "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", "license": "MIT" }, + "node_modules/hermes-compiler": { + "version": "250829098.0.17", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.17.tgz", + "integrity": "sha512-qG1PXzTEtriF6oQLZF3vyHhSMxOdW5h2TqqLri0rdpstPustd2fSvRZQMVAPdlhgFwBfYnj3OUZtiO6LjYsEFw==", + "license": "MIT" + }, "node_modules/hermes-estree": { "version": "0.29.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "dev": true, "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.29.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "dev": true, "license": "MIT", "dependencies": { "hermes-estree": "0.29.1" @@ -23691,21 +22598,6 @@ "node": ">= 4" } }, - "node_modules/image-size": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", - "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", - "license": "MIT", - "dependencies": { - "queue": "6.0.2" - }, - "bin": { - "image-size": "bin/image-size.js" - }, - "engines": { - "node": ">=16.x" - } - }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", @@ -23754,6 +22646,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -23777,6 +22670,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -23789,12 +22683,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, "node_modules/inline-style-parser": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", @@ -23898,22 +22786,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -24027,6 +22899,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -24149,6 +23022,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -24210,22 +23084,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-nan": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", - "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -24292,6 +23150,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -24397,6 +23256,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -24518,6 +23378,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -24527,6 +23388,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", @@ -24543,6 +23405,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -24644,23 +23507,6 @@ } } }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -24674,6 +23520,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -24715,6 +23562,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", @@ -24735,6 +23583,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -24744,6 +23593,7 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", @@ -24758,6 +23608,7 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" @@ -25574,9 +24425,9 @@ } }, "node_modules/lan-network": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.1.7.tgz", - "integrity": "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.2.1.tgz", + "integrity": "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==", "license": "MIT", "bin": { "lan-network": "dist/lan-network-cli.js" @@ -26077,6 +24928,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/linkify-it": { @@ -26915,45 +25767,43 @@ } }, "node_modules/metro": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz", - "integrity": "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.5.tgz", + "integrity": "sha512-r1liLkyFZMVSEMNjU1CJU5pRzs3NdkxHqXS60O25c0rCIqAR+cGk7rPydw/g0WAIKVXojIBIF45yYBPagJGcgw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", + "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", - "@babel/types": "^7.25.2", - "accepts": "^1.3.7", - "chalk": "^4.0.0", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", - "hermes-parser": "0.32.0", - "image-size": "^1.0.2", + "hermes-parser": "0.35.0", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-config": "0.83.3", - "metro-core": "0.83.3", - "metro-file-map": "0.83.3", - "metro-resolver": "0.83.3", - "metro-runtime": "0.83.3", - "metro-source-map": "0.83.3", - "metro-symbolicate": "0.83.3", - "metro-transform-plugins": "0.83.3", - "metro-transform-worker": "0.83.3", - "mime-types": "^2.1.27", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-config": "0.84.5", + "metro-core": "0.84.5", + "metro-file-map": "0.84.5", + "metro-resolver": "0.84.5", + "metro-runtime": "0.84.5", + "metro-source-map": "0.84.5", + "metro-symbolicate": "0.84.5", + "metro-transform-plugins": "0.84.5", + "metro-transform-worker": "0.84.5", + "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", @@ -26965,64 +25815,65 @@ "metro": "src/cli.js" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-babel-transformer": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.83.3.tgz", - "integrity": "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.5.tgz", + "integrity": "sha512-2WbHILKMiJUzfdjmGOQOqU1bWi9//gqiclc/tkk/AIsrrVw3efhZ1uhkOwMTxUEPOzqoo091H0olLmVZH5FHGQ==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", - "hermes-parser": "0.32.0", + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.5", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-babel-transformer/node_modules/hermes-estree": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", - "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", "license": "MIT" }, "node_modules/metro-babel-transformer/node_modules/hermes-parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", - "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", "dependencies": { - "hermes-estree": "0.32.0" + "hermes-estree": "0.35.0" } }, "node_modules/metro-cache": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.83.3.tgz", - "integrity": "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.5.tgz", + "integrity": "sha512-WHS0n2OxQqtwEjSeQFPePNrMvEFhmQcUQM9cRJMHByWoi/GMWFBEWOf7hVkAM/0KRutAXNbDlSu/cZB6CyxgQQ==", "license": "MIT", "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", - "metro-core": "0.83.3" + "metro-core": "0.84.5" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-cache-key": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.83.3.tgz", - "integrity": "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.5.tgz", + "integrity": "sha512-3dPB2TnvGjjf0/9O7AXVQURKXuQNauTZE7WpTGTlR017Gh/B5y0m/2wcqxfveUguHSpu89KhVxCAlr2k/H7uhQ==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-cache/node_modules/agent-base": { @@ -27048,42 +25899,206 @@ } }, "node_modules/metro-config": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.83.3.tgz", - "integrity": "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA==", + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.6.tgz", + "integrity": "sha512-cD2mLEofcuV26kxSV4hfV1Pbuh6igdUhYQriO8ZVeJ7HyZfq4/wqHV0gSR7fEO8NUp9odr60/Kzm5YakmghWwQ==", "license": "MIT", "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", - "metro": "0.83.3", - "metro-cache": "0.83.3", - "metro-core": "0.83.3", - "metro-runtime": "0.83.3", + "metro": "0.84.6", + "metro-cache": "0.84.6", + "metro-core": "0.84.6", + "metro-runtime": "0.84.6", "yaml": "^2.6.1" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-core": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.83.3.tgz", - "integrity": "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw==", + "node_modules/metro-config/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/metro-config/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/metro-config/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/metro-config/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/metro-config/node_modules/hermes-estree": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", + "license": "MIT" + }, + "node_modules/metro-config/node_modules/hermes-parser": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/metro-config/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/metro-config/node_modules/metro": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.6.tgz", + "integrity": "sha512-ty/tx/imE5Ph2gvPU788Ckim6RAC2tyZxLz2hWRgC9U7/fGKV7qY/slADy0qHPEw9cpUgc4BfmV3oUsYwm7oeg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.35.0", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.84.6", + "metro-cache": "0.84.6", + "metro-cache-key": "0.84.6", + "metro-config": "0.84.6", + "metro-core": "0.84.6", + "metro-file-map": "0.84.6", + "metro-resolver": "0.84.6", + "metro-runtime": "0.84.6", + "metro-source-map": "0.84.6", + "metro-symbolicate": "0.84.6", + "metro-transform-plugins": "0.84.6", + "metro-transform-worker": "0.84.6", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-babel-transformer": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.6.tgz", + "integrity": "sha512-B1ozl6KxFHbQjXZ2U8WiTPWXylqiD3V4EXyV5r0fqETOrqIrJlBvbVTD82UxIN+B3Vpe4l8G1tb15ocd2RyOQA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-cache": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.6.tgz", + "integrity": "sha512-KBJVpb02oKNO+jlWQ1Aax7cd11YP0MClDaMgx6C4MhyZ9g95J/dC1Bo6sCzXaU9L9h/w5cQfT5zDkGW5sOj99A==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.84.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-cache-key": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.6.tgz", + "integrity": "sha512-6tyXt1BZ/3U183XV48oif7Nm65TE+pTo0Vs31u4FxMgqiYQR/SiSr3RoXn3pmy4pd280ZmLmct0x3jZpu0pV4A==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-core": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.6.tgz", + "integrity": "sha512-ZqYskM8+f3PFMosBDJd8DLqRvT1ltRGhWL/ZfTpBvf4SoadO30VVrdhAoHFVGz3G1CJpWa3fgZH7nnnX/ybllA==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", - "metro-resolver": "0.83.3" + "metro-resolver": "0.84.6" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-file-map": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.83.3.tgz", - "integrity": "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA==", + "node_modules/metro-config/node_modules/metro-file-map": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.6.tgz", + "integrity": "sha512-ov9VywWBsHPt54Zc7/DxWvqjTwxuZvhfeyHg8ZAMGKtf2PcH1wS3EnoBH7In53Rspk/eXVWAO5+avxunPn081w==", "license": "MIT", "dependencies": { "debug": "^4.4.0", @@ -27097,66 +26112,279 @@ "walker": "^1.0.7" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-minify-terser": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.83.3.tgz", - "integrity": "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ==", + "node_modules/metro-config/node_modules/metro-minify-terser": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.6.tgz", + "integrity": "sha512-SqhB/Kxrw0XfyW0k8mEscqX/CQopm6Fp3EpdSIPzvKfGgQp9bTMahg9PAdVsXUmIWwErbmFw1VqB+VFBOKksUw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/metro-resolver": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.83.3.tgz", - "integrity": "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ==", + "node_modules/metro-config/node_modules/metro-resolver": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.6.tgz", + "integrity": "sha512-PplpGc/OCLxgKeLNsLQO/VHsYDIvkcGGr3zNT7UanHCGRqhxKv245o+naV8cRI4/pcLqyc+9j+J0AJbT3Kp5Sg==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-source-map": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.6.tgz", + "integrity": "sha512-4p/EplRbgNxhdqA6kAj1AmIq9qqYXYSAjgxuZ73rYA+p037xDDrxK8CyDKNfbn1k6aMuVt8LV0fpt7NHUTKiZw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.84.6", + "nullthrows": "^1.1.1", + "ob1": "0.84.6", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-symbolicate": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.6.tgz", + "integrity": "sha512-wJFyyF5ysbVyoYVWGL6GwVMiNnGllwDU2gF096376fl0fc8IFUlADSyNlswj31K9og2sOilXe/FdyWFPczPUYg==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.84.6", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-transform-plugins": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.6.tgz", + "integrity": "sha512-pROPMFaj25Y9+3LlLqpBRz/7B/2YPnfEQz/z3juYxkh3FGQ+3c/Qh4E+khPSTdwTw0M6LitLYHMqaHMbQmuBJw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/metro-transform-worker": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.6.tgz", + "integrity": "sha512-xLTVrOENaHR9DiuhnHS+zcle0rKsCy2CpXSIx7xD+zhJs+qVRNUyV7Z1zIt/0P/d0cSGVx846R+dIjHEudhcww==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.84.6", + "metro-babel-transformer": "0.84.6", + "metro-cache": "0.84.6", + "metro-cache-key": "0.84.6", + "metro-minify-terser": "0.84.6", + "metro-source-map": "0.84.6", + "metro-transform-plugins": "0.84.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/metro-config/node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/metro-config/node_modules/ob1": { + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.6.tgz", + "integrity": "sha512-+s+6zjd0X68hfAcn92NsEPXnSYOF3O7exw/Fj4UfRTB+UL+Tdjdkzu5/4WquXlzqgvNm8FWuuW6/0Yd8S2rYxw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-config/node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/metro-core": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.5.tgz", + "integrity": "sha512-xwm605hCi5Y6eJTTb8ZWo6pkUcoBEIyiQOfkZh5GwtDwUrP9SNhTQZhzJHrBCwwxlf3Ptl/pxWJgQ1rsNYMnrA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.84.5" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-file-map": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.5.tgz", + "integrity": "sha512-mlm/JL8toSbSc2akpKIGmzvrVRSCgZ5vkbycI34oMLoOnLGuLyC8WTyVJ6P0hZG/usDaGwZSl/s9BCRriqjGJA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.5.tgz", + "integrity": "sha512-BJoFwCEDsYnagPqarayInv2+diCDNDdLlaof/p6s9w4gh+gc9HXYM+pDvsKGKKUumpZswNF3Z/ftTMqKl/5IBg==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-resolver": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.5.tgz", + "integrity": "sha512-VSSnepg1k6LyCwtb6eirWdAWlpKwBG8Rdtsr1mU38rMelFyWgh3/QuMSiZIZAIjwg/fsa8GhW5/FO54CAUPCEA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-runtime": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.83.3.tgz", - "integrity": "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw==", + "version": "0.84.6", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.6.tgz", + "integrity": "sha512-47EYO/DOai0PA3GoAyDpyXOgHNMwbl/Z9dQlQineDLHkpD42xOwMrIx1crT0+n6F+aGoEyxZmeFwfMzaIqVqKQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-source-map": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.83.3.tgz", - "integrity": "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.5.tgz", + "integrity": "sha512-2BtV5L9uPc49F13Gn5wiP6bX/EncqzqTIk2VL/0F/96Vo0YEOjluT/qktQjFODfqGFsucwnh5mPEAl/2jVEfeg==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.3", - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", - "@babel/types": "^7.25.2", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-symbolicate": "0.83.3", + "metro-symbolicate": "0.84.5", "nullthrows": "^1.1.1", - "ob1": "0.83.3", + "ob1": "0.84.5", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-source-map/node_modules/source-map": { @@ -27169,14 +26397,14 @@ } }, "node_modules/metro-symbolicate": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.83.3.tgz", - "integrity": "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.5.tgz", + "integrity": "sha512-rQ40zYDAkaWBN9yvjUuAD0ZpzBMZSoKyGYXnb5JrfbKjun7fTvfoLHL3KXFYenBTYZkQtlp4cKSCv/1utxFyOw==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", - "metro-source-map": "0.83.3", + "metro-source-map": "0.84.5", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" @@ -27185,7 +26413,7 @@ "metro-symbolicate": "src/index.js" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-symbolicate/node_modules/source-map": { @@ -27198,44 +26426,57 @@ } }, "node_modules/metro-transform-plugins": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.83.3.tgz", - "integrity": "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.5.tgz", + "integrity": "sha512-+InaSVGaOyt0DyRo4Y/zIdPI6CZwnbNho5LAL23tgmuGwv7fyfkF7kKfPjZcfxXBcoYdTLLFnCfCH/dHSiCqNg==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.3", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/metro-transform-worker": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.83.3.tgz", - "integrity": "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.5.tgz", + "integrity": "sha512-ui1Z8x4s5RL36gMmKLaMMO7O9NNDHNdthEZSCDQHAau3JcAsTaFOK6I+2q4I/kW5u8hSEjJk9L45TXSVJw6g1A==", "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", - "@babel/generator": "^7.25.0", - "@babel/parser": "^7.25.3", - "@babel/types": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", - "metro": "0.83.3", - "metro-babel-transformer": "0.83.3", - "metro-cache": "0.83.3", - "metro-cache-key": "0.83.3", - "metro-minify-terser": "0.83.3", - "metro-source-map": "0.83.3", - "metro-transform-plugins": "0.83.3", + "metro": "0.84.5", + "metro-babel-transformer": "0.84.5", + "metro-cache": "0.84.5", + "metro-cache-key": "0.84.5", + "metro-minify-terser": "0.84.5", + "metro-source-map": "0.84.5", + "metro-transform-plugins": "0.84.5", "nullthrows": "^1.1.1" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/metro/node_modules/ci-info": { @@ -27244,19 +26485,96 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", "license": "MIT" }, + "node_modules/metro/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/metro/node_modules/hermes-estree": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.32.0.tgz", - "integrity": "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", "license": "MIT" }, "node_modules/metro/node_modules/hermes-parser": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.32.0.tgz", - "integrity": "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw==", + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", "dependencies": { - "hermes-estree": "0.32.0" + "hermes-estree": "0.35.0" + } + }, + "node_modules/metro/node_modules/metro-config": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.5.tgz", + "integrity": "sha512-zie+uN6oohscowi2S7ByU+wUw6CrT4ZxW9uAbONOObSxx86RGmnIAmjXHLkfmcdYoY7jzOPEbqcI6oeVmqyBQA==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.5", + "metro-cache": "0.84.5", + "metro-core": "0.84.5", + "metro-runtime": "0.84.5", + "yaml": "^2.6.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro/node_modules/metro-runtime": { + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.5.tgz", + "integrity": "sha512-U1m2+d1Pr+JO2/iVXBB2OfXXityz7tqwIorxfrT15IEgaHvpJBq/OHiqnOWPKJbUl3JcxjcdviZZOKk85oK4Qg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/metro/node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "license": "MIT", + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/metro/node_modules/source-map": { @@ -27269,9 +26587,9 @@ } }, "node_modules/metro/node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", "license": "MIT", "engines": { "node": ">=8.3.0" @@ -28305,6 +27623,12 @@ "dev": true, "license": "MIT" }, + "node_modules/multitars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/multitars/-/multitars-1.0.2.tgz", + "integrity": "sha512-6GwVw5eLi9sThdtlS4PKwC7yRLaf45pYhIEzKBHdKxi+YOXGKFX8acIniH+Uh/+k9mS2lQOupTccjoe5r0/1IQ==", + "license": "MIT" + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -28406,6 +27730,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -28422,9 +27747,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -28492,12 +27817,6 @@ "node": ">= 0.6" } }, - "node_modules/nested-error-stacks": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.0.1.tgz", - "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", - "license": "MIT" - }, "node_modules/node-abi": { "version": "4.28.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.28.0.tgz", @@ -28796,6 +28115,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -28814,6 +28134,31 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/noxcturnal": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/noxcturnal/-/noxcturnal-0.1.5.tgz", + "integrity": "sha512-X/HQXJP/xn7LVQ4z1E4La0NHSl5UHdtJPG6ky4r2/Xgb7k79nGDJgBXk7I5f1V2vInWjlSCM14oSB0cUxwZS/Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@oxc-project/types": "0.154.0" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@noxcturnal/noxcturnal-darwin-arm64": "0.1.5", + "@noxcturnal/noxcturnal-darwin-x64": "0.1.5", + "@noxcturnal/noxcturnal-linux-arm64-gnu": "0.1.5", + "@noxcturnal/noxcturnal-linux-arm64-musl": "0.1.5", + "@noxcturnal/noxcturnal-linux-x64-gnu": "0.1.5", + "@noxcturnal/noxcturnal-linux-x64-musl": "0.1.5", + "@noxcturnal/noxcturnal-win32-arm64-msvc": "0.1.5", + "@noxcturnal/noxcturnal-win32-x64-msvc": "0.1.5" + } + }, "node_modules/npm-package-arg": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz", @@ -28873,15 +28218,15 @@ "license": "MIT" }, "node_modules/ob1": { - "version": "0.83.3", - "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.83.3.tgz", - "integrity": "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA==", + "version": "0.84.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.5.tgz", + "integrity": "sha512-aH9RkoZc7w/90HBamFxTw8ZLFr05wXS+iOnvmrgo53Ep8Pyrm5FieQSaPIVROkfFVQISeD/zo92fes26TOwe+A==", "license": "MIT", "dependencies": { "flow-enums-runtime": "^0.0.6" }, "engines": { - "node": ">=20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, "node_modules/object-assign": { @@ -28905,26 +28250,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -28944,6 +28274,7 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -29358,6 +28689,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -29644,6 +28976,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -29818,6 +29151,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -30010,15 +29344,16 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz", + "integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==", "funding": [ { "type": "opencollective", @@ -30035,9 +29370,9 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.20", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" @@ -30087,18 +29422,6 @@ "node": ">=6.0.0" } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", @@ -30310,6 +29633,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -30542,15 +29866,6 @@ "dev": true, "license": "MIT" }, - "node_modules/queue": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", - "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "license": "MIT", - "dependencies": { - "inherits": "~2.0.3" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -30627,34 +29942,10 @@ "node": ">=0.10.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", - "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", + "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -30692,17 +29983,23 @@ } }, "node_modules/react-dom": { - "version": "19.1.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz", - "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", "license": "MIT", "dependencies": { - "scheduler": "^0.26.0" + "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.1.0" + "react": "^19.2.3" } }, + "node_modules/react-dom/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/react-fast-compare": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", @@ -30798,57 +30095,59 @@ } }, "node_modules/react-native": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz", - "integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==", + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.86.3.tgz", + "integrity": "sha512-JR5s3bM9ezud+Mw24GlNXNfthqPIKwrQgPPJcam+L97t2sKjjEavhCzBn+fyqZZRcM5+XlhYxpTxVkK7e1n38Q==", "license": "MIT", "dependencies": { - "@jest/create-cache-key-function": "^29.7.0", - "@react-native/assets-registry": "0.81.5", - "@react-native/codegen": "0.81.5", - "@react-native/community-cli-plugin": "0.81.5", - "@react-native/gradle-plugin": "0.81.5", - "@react-native/js-polyfills": "0.81.5", - "@react-native/normalize-colors": "0.81.5", - "@react-native/virtualized-lists": "0.81.5", + "@react-native/assets-registry": "0.86.3", + "@react-native/codegen": "0.86.3", + "@react-native/community-cli-plugin": "0.86.3", + "@react-native/gradle-plugin": "0.86.3", + "@react-native/js-polyfills": "0.86.3", + "@react-native/normalize-colors": "0.86.3", + "@react-native/virtualized-lists": "0.86.3", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", - "babel-jest": "^29.7.0", - "babel-plugin-syntax-hermes-parser": "0.29.1", + "babel-plugin-syntax-hermes-parser": "0.36.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", - "glob": "^7.1.1", + "hermes-compiler": "250829098.0.17", "invariant": "^2.2.4", - "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", - "metro-runtime": "^0.83.1", - "metro-source-map": "^0.83.1", + "metro-runtime": "^0.84.3", + "metro-source-map": "^0.84.3", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", - "scheduler": "0.26.0", + "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", "whatwg-fetch": "^3.0.0", - "ws": "^6.2.3", + "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "react-native": "cli.js" }, "engines": { - "node": ">= 20.19.4" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" }, "peerDependencies": { - "@types/react": "^19.1.0", - "react": "^19.1.0" + "@react-native/jest-preset": "0.86.3", + "@types/react": "^19.1.1", + "react": "^19.2.3" }, "peerDependenciesMeta": { + "@react-native/jest-preset": { + "optional": true + }, "@types/react": { "optional": true } @@ -30868,6 +30167,22 @@ "react-native-reanimated": ">=2.8.0" } }, + "node_modules/react-native-drawer-layout": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/react-native-drawer-layout/-/react-native-drawer-layout-4.2.12.tgz", + "integrity": "sha512-qYmntEctkMSodN7pnC2llV21nswImLFPHJeT3PJXSJqZdU4jzDATR8iVi66sXkrtoOLJ2+EvXxgd7sMMpV4ViA==", + "license": "MIT", + "dependencies": { + "color": "^4.2.3", + "use-latest-callback": "^0.2.4" + }, + "peerDependencies": { + "react": ">= 18.2.0", + "react-native": "*", + "react-native-gesture-handler": ">= 2.0.0", + "react-native-reanimated": ">= 2.0.0" + } + }, "node_modules/react-native-edge-to-edge": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/react-native-edge-to-edge/-/react-native-edge-to-edge-1.8.1.tgz", @@ -30879,12 +30194,13 @@ } }, "node_modules/react-native-gesture-handler": { - "version": "2.28.0", - "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.28.0.tgz", - "integrity": "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A==", + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.32.0.tgz", + "integrity": "sha512-uYIMOKlKENORq2SABE+jIjbPU+h5I/sQKcq2v16zRq848nwEp1fWRVwML4QWqijc8UcXJC25o54S8GQd4Mf2OA==", "license": "MIT", "dependencies": { "@egjs/hammerjs": "^2.0.17", + "@types/react-test-renderer": "^19.1.0", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, @@ -30914,9 +30230,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.3.1.tgz", - "integrity": "sha512-KhGsS0YkCA+gusgyzlf9hnqzVPIR398KTpqXyqq/+yYJJPAvyEEPKcxlB0xtOOXSMrR2A9uRKVARVQhZwrOh+Q==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.5.1.tgz", + "integrity": "sha512-RnMvtDuR+68ig864gAvZCOdZehqhC5rFmMo0kn+ARfgVSTvFeF6IFLBVgMPUu0KwihaapEyW24WRi6nEyy1kSA==", "license": "MIT", "dependencies": { "react-native-is-edge-to-edge": "^1.3.1", @@ -30924,14 +30240,14 @@ }, "peerDependencies": { "react": "*", - "react-native": "0.81 - 0.85", - "react-native-worklets": "0.8.x" + "react-native": "0.83 - 0.86", + "react-native-worklets": "0.10.x" } }, "node_modules/react-native-safe-area-context": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.6.2.tgz", - "integrity": "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-5.7.0.tgz", + "integrity": "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==", "license": "MIT", "peerDependencies": { "react": "*", @@ -30939,13 +30255,12 @@ } }, "node_modules/react-native-screens": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.16.0.tgz", - "integrity": "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q==", + "version": "4.30.0", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.30.0.tgz", + "integrity": "sha512-FrZG/Q5gqoDu0SgP4d2Ly0qdio5DR1KdGPEYImhkz7tmrhpML4C39m6RYLGd5TVLHZwcCh8NPvW9rylevjD0uQ==", "license": "MIT", "dependencies": { "react-freeze": "^1.0.0", - "react-native-is-edge-to-edge": "^1.2.1", "warn-once": "^0.1.0" }, "peerDependencies": { @@ -30953,20 +30268,29 @@ "react-native": "*" } }, - "node_modules/react-native-svg": { - "version": "15.15.3", - "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.3.tgz", - "integrity": "sha512-/k4KYwPBLGcx2f5d4FjE+vCScK7QOX14cl2lIASJ28u4slHHtIhL0SZKU7u9qmRBHxTCKPoPBtN6haT1NENJNA==", - "license": "MIT", - "dependencies": { - "css-select": "^5.1.0", - "css-tree": "^1.1.3", - "warn-once": "0.1.1" - }, - "peerDependencies": { - "react": "*", - "react-native": "*" - } + "node_modules/react-native-skia-android": { + "version": "147.1.0", + "resolved": "https://registry.npmjs.org/react-native-skia-android/-/react-native-skia-android-147.1.0.tgz", + "integrity": "sha512-pWA0M0G74AhjEop0HLCkjWJMup2HJxOmuUjfPt6kSDhYeWKVx8AEzWh0Fh19ah78zE/s4hD0Of0Tyem5shhiTg==", + "license": "MIT" + }, + "node_modules/react-native-skia-apple-ios": { + "version": "147.1.0", + "resolved": "https://registry.npmjs.org/react-native-skia-apple-ios/-/react-native-skia-apple-ios-147.1.0.tgz", + "integrity": "sha512-cr4rWe4Bf0H0TTutUp5cgHt5/Felttl1bh4BAAAsgAeL2F10FAK9urX8spjUshzMwjqXD7rNOWuFzU6ZcNlGKw==", + "license": "MIT" + }, + "node_modules/react-native-skia-apple-macos": { + "version": "147.1.0", + "resolved": "https://registry.npmjs.org/react-native-skia-apple-macos/-/react-native-skia-apple-macos-147.1.0.tgz", + "integrity": "sha512-Qbv0Y7LgawtRKuGk8gnGeh8nDWwNiu03LcX0mVaQzBBbxFDYvqejanA+AkO3p8gsQb+fsXRc9DAk+U8cBnzZvA==", + "license": "MIT" + }, + "node_modules/react-native-skia-apple-tvos": { + "version": "147.1.0", + "resolved": "https://registry.npmjs.org/react-native-skia-apple-tvos/-/react-native-skia-apple-tvos-147.1.0.tgz", + "integrity": "sha512-b+4vILXHPu++t8H41PHLBVsTab2LPqwXNdzgdScyl4+Cu8Ta34aUQW3T469cB0ogAMPdu//KV00w4YVpDZoRUQ==", + "license": "MIT" }, "node_modules/react-native-unistyles": { "version": "3.2.4", @@ -31043,44 +30367,89 @@ } }, "node_modules/react-native-worklets": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.8.3.tgz", - "integrity": "sha512-oCBJROyLU7yG/1R8s0INMflygTH71bx+5XcYkH0CM938TlhSoVbiunE1WVW5FZa51vwYqfLie/IXMX2s1Kh3eg==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.10.1.tgz", + "integrity": "sha512-62mRM19bDpfpdI8HLkEErcdOsrAPDtE9lA/sw+5lLRpzBHNhxaoj9QyY2KjXqUmirelxkX4zuPGTC3VdA0feJA==", "license": "MIT", "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", "@babel/plugin-transform-shorthand-properties": "^7.27.1", "@babel/plugin-transform-template-literals": "^7.27.1", "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/preset-typescript": "^7.27.1", + "@babel/preset-typescript": "^7.28.5", + "@babel/types": "^7.27.1", "convert-source-map": "^2.0.0", - "semver": "^7.7.3" + "semver": "^7.7.4" }, "peerDependencies": { "@babel/core": "*", "@react-native/metro-config": "*", "react": "*", - "react-native": "0.81 - 0.85" + "react-native": "0.83 - 0.86" } }, - "node_modules/react-native/node_modules/@react-native/normalize-colors": { - "version": "0.81.5", - "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.81.5.tgz", - "integrity": "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==", - "license": "MIT" - }, - "node_modules/react-native/node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "node_modules/react-native/node_modules/@react-native/codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", + "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/react-native/node_modules/@react-native/community-cli-plugin": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.86.3.tgz", + "integrity": "sha512-qSDL9LQc5mZSZPNczT95WU9YQuPzxBklgON9vLhhqfI0yWIwKInqFx88dQ/uiEXBtf0yossthaQIqA4Ml6bF6g==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.86.3", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.84.3", + "metro-config": "^0.84.3", + "metro-core": "^0.84.3", + "semver": "^7.1.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.86.3" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/react-native/node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.0.tgz", + "integrity": "sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.0" } }, "node_modules/react-native/node_modules/commander": { @@ -31092,37 +30461,19 @@ "node": ">=18" } }, - "node_modules/react-native/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "node_modules/react-native/node_modules/hermes-estree": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", + "license": "MIT" }, - "node_modules/react-native/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", + "node_modules/react-native/node_modules/hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "hermes-estree": "0.36.0" } }, "node_modules/react-native/node_modules/react-refresh": { @@ -31134,13 +30485,31 @@ "node": ">=0.10.0" } }, + "node_modules/react-native/node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, "node_modules/react-native/node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", "license": "MIT", - "dependencies": { - "async-limiter": "~1.0.0" + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/react-reconciler": { @@ -31168,6 +30537,7 @@ "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -31719,28 +31089,6 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, - "node_modules/requireg": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/requireg/-/requireg-0.2.2.tgz", - "integrity": "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg==", - "dependencies": { - "nested-error-stacks": "~2.0.1", - "rc": "~1.2.7", - "resolve": "~1.7.1" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/requireg/node_modules/resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", - "license": "MIT", - "dependencies": { - "path-parse": "^1.0.5" - } - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -31819,15 +31167,6 @@ "integrity": "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w==", "license": "MIT" }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -31883,65 +31222,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -32190,6 +31470,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -32218,6 +31499,18 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sandbox-cli-detector": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sandbox-cli-detector/-/sandbox-cli-detector-0.2.0.tgz", + "integrity": "sha512-4lyHX0ZU0AZKwjgZ1InxZAa3PNpyEb8rOQ+Zss1ReYmhNzW0Q+h1zE5nvniXN0HaAWZaZE1zgVNEirb0R7LmNg==", + "license": "MIT", + "bin": { + "sandbox-cli-detector": "dist/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, "node_modules/sanitize-filename": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", @@ -32254,6 +31547,7 @@ "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "dev": true, "license": "MIT" }, "node_modules/secure-json-parse": { @@ -32420,6 +31714,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -32973,9 +32268,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -33116,6 +32411,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -33128,6 +32424,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -33200,6 +32497,12 @@ "node": ">=8" } }, + "node_modules/standard-navigation": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/standard-navigation/-/standard-navigation-0.0.5.tgz", + "integrity": "sha512-YAmzwAiiQVocZxO/VGPFiQHcu5pKiz09QIGC0MK6aRMoa3E0QkoTQgcqJr7ZZ3OMiNhu4DkaGElFI5htjOIDbw==", + "license": "MIT" + }, "node_modules/standardwebhooks": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", @@ -33720,6 +33023,18 @@ "url": "https://opencollective.com/synckit" } }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tailwindcss": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", @@ -33874,6 +33189,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -33888,6 +33204,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -33899,6 +33216,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -33919,6 +33237,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -33941,6 +33260,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -33950,6 +33270,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -34113,6 +33434,12 @@ "node": ">=0.6" } }, + "node_modules/toqr": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/toqr/-/toqr-0.1.1.tgz", + "integrity": "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA==", + "license": "MIT" + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -34213,19 +33540,6 @@ "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", "license": "MIT" }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, "node_modules/ts-declaration-location": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", @@ -34272,6 +33586,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true, "license": "Apache-2.0" }, "node_modules/ts-jest": { @@ -34514,6 +33829,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -35041,6 +34357,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -35125,19 +34442,6 @@ "dev": true, "license": "(WTFPL OR MIT)" }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -35667,52 +34971,11 @@ "webidl-conversions": "^3.0.0" } }, - "node_modules/whatwg-url-without-unicode": { - "version": "8.0.0-3", - "resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz", - "integrity": "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==", - "license": "MIT", - "dependencies": { - "buffer": "^5.4.3", - "punycode": "^2.1.1", - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/whatwg-url-without-unicode/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/whatwg-url-without-unicode/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=8" - } + "node_modules/whatwg-url-minimum": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.1.2.tgz", + "integrity": "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==", + "license": "MIT" }, "node_modules/which": { "version": "2.0.2", @@ -35806,6 +35069,7 @@ "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", @@ -35857,6 +35121,7 @@ "version": "6.3.5", "resolved": "https://registry.npmjs.org/wonka/-/wonka-6.3.5.tgz", "integrity": "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw==", + "dev": true, "license": "MIT" }, "node_modules/word-wrap": { @@ -36213,6 +35478,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -36295,6 +35561,19 @@ "zod": "^3.25 || ^4" } }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, "node_modules/zustand": { "version": "5.0.11", "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", @@ -36347,6 +35626,34 @@ "node": ">= 12.17.0" } }, + "node_modules/zxing-wasm": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-3.1.3.tgz", + "integrity": "sha512-3lC9BJk4fR5ZJxcGjb0hVnDFOW7KpLXHIebiBmVd4FDRQZVeObztoTKxRUPxlWwSgxrMRONK0u50hBD1aTYEKg==", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.41.5", + "type-fest": "^5.8.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } + }, + "node_modules/zxing-wasm/node_modules/type-fest": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.10.0.tgz", + "integrity": "sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "packages/app": { "name": "@getpaseo/app", "version": "0.12.0", @@ -36370,11 +35677,11 @@ "@marijn/find-cluster-break": "^1.0.2", "@mattermost/react-native-paste-input": "2.0.1", "@react-native-async-storage/async-storage": "2.2.0", - "@react-native-masked-view/masked-view": "^0.3.2", - "@react-native/normalize-colors": "^0.81.5", + "@react-native-masked-view/masked-view": "0.3.2", + "@react-native/normalize-colors": "0.86.3", "@react-navigation/native": "^7.1.8", "@replit/codemirror-vim": "6.3.0", - "@shopify/react-native-skia": "2.2.12", + "@shopify/react-native-skia": "2.6.2", "@tanstack/react-query": "^5.90.11", "@tanstack/react-virtual": "^3.13.21", "@xterm/addon-clipboard": "^0.3.0-beta.213", @@ -36387,30 +35694,30 @@ "@xterm/addon-webgl": "^0.20.0-beta.212", "@xterm/xterm": "^6.1.0-beta.213", "buffer": "^6.0.3", - "expo": "^54.0.18", - "expo-asset": "~12.0.12", - "expo-audio": "~1.0.13", - "expo-build-properties": "^1.0.9", - "expo-camera": "~17.0.10", - "expo-clipboard": "~8.0.7", - "expo-constants": "~18.0.9", - "expo-crypto": "^15.0.8", - "expo-dev-client": "^6.0.15", - "expo-document-picker": "~14.0.8", - "expo-file-system": "~19.0.17", - "expo-haptics": "~15.0.7", - "expo-image": "~3.0.10", - "expo-image-manipulator": "~14.0.8", - "expo-image-picker": "^17.0.8", - "expo-keep-awake": "^15.0.7", - "expo-linking": "~8.0.8", - "expo-localization": "~17.0.9", - "expo-notifications": "^0.32.16", - "expo-router": "~6.0.13", - "expo-sharing": "^14.0.8", - "expo-splash-screen": "~31.0.10", - "expo-sqlite": "~16.0.10", - "expo-system-ui": "~6.0.7", + "expo": "~57.0.30", + "expo-asset": "~57.0.20", + "expo-audio": "~57.0.5", + "expo-build-properties": "~57.0.22", + "expo-camera": "~57.0.6", + "expo-clipboard": "~57.0.2", + "expo-constants": "~57.0.22", + "expo-crypto": "~57.0.4", + "expo-dev-client": "~57.0.20", + "expo-document-picker": "~57.0.3", + "expo-file-system": "~57.0.7", + "expo-haptics": "~57.0.3", + "expo-image": "~57.0.5", + "expo-image-manipulator": "~57.0.21", + "expo-image-picker": "~57.0.20", + "expo-keep-awake": "~57.0.2", + "expo-linking": "~57.0.13", + "expo-localization": "~57.0.2", + "expo-notifications": "~57.0.23", + "expo-router": "~57.0.28", + "expo-sharing": "~57.0.23", + "expo-splash-screen": "~57.0.10", + "expo-sqlite": "~57.0.4", + "expo-system-ui": "~57.0.4", "fast-deep-equal": "^3.1.3", "htmlparser2": "^12.0.0", "i18next": "^26.3.0", @@ -36423,25 +35730,25 @@ "micromark-util-decode-string": "2.0.1", "mnemonic-id": "^3.2.7", "qrcode": "^1.5.4", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.2.3", + "react-dom": "19.2.3", "react-freeze": "1.0.4", "react-i18next": "^17.0.8", - "react-native": "0.81.5", + "react-native": "0.86.3", "react-native-draggable-flatlist": "^4.0.3", "react-native-edge-to-edge": "^1.7.0", "react-native-enriched-markdown": "1.2.0-nightly-20261014-766fc0e67", - "react-native-gesture-handler": "~2.28.0", + "react-native-gesture-handler": "~2.32.0", "react-native-keyboard-controller": "1.21.12", "react-native-nitro-modules": "0.35.5", - "react-native-reanimated": "~4.3.1", - "react-native-safe-area-context": "~5.6.0", - "react-native-screens": "~4.16.0", - "react-native-svg": "^15.14.0", + "react-native-reanimated": "4.5.1", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0", + "react-native-svg": "15.15.4", "react-native-unistyles": "^3.2.4", "react-native-web": "~0.21.0", - "react-native-webview": "^13.16.0", - "react-native-worklets": "~0.8.3", + "react-native-webview": "13.16.1", + "react-native-worklets": "0.10.1", "tiny-invariant": "^1.3.3", "turndown": "^7.2.4", "turndown-plugin-gfm": "^1.0.2", @@ -36463,11 +35770,12 @@ "@vitest/browser": "^4.1.7", "@vitest/browser-playwright": "^4.1.7", "@xterm/headless": "^6.1.0-beta.213", + "babel-preset-expo": "~57.0.16", "dotenv": "^17.2.3", "eas-cli": "^16.24.1", "esbuild": "0.28.1", "eslint": "^9.25.0", - "eslint-config-expo": "~10.0.0", + "eslint-config-expo": "~57.0.2", "expo-gradle-jvmargs": "^1.1.2", "fake-indexeddb": "^6.2.5", "jsdom": "^20.0.3", @@ -37007,6 +36315,149 @@ "node": ">=18" } }, + "packages/app/node_modules/@expo/config-plugins": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-57.0.10.tgz", + "integrity": "sha512-XFcj01blofSohoOxibrPsrsFPt2gAigrcWE3s6Vg+rSHvP9QVEfnyfmJNVsuIVT0EjY/1rZVJ4SajNDR5cJjpA==", + "license": "MIT", + "dependencies": { + "@expo/config-types": "^57.0.2", + "@expo/json-file": "~11.0.1", + "@expo/plist": "^0.8.1", + "@expo/require-utils": "^57.0.6", + "@expo/sdk-runtime-versions": "^1.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.5.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/app/node_modules/@expo/config-plugins/node_modules/@expo/json-file": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.0.1.tgz", + "integrity": "sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/app/node_modules/@expo/config-types": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-57.0.2.tgz", + "integrity": "sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==", + "license": "MIT" + }, + "packages/app/node_modules/@expo/image-utils": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.11.6.tgz", + "integrity": "sha512-rmMpn7QGp6pUGRCQ3vvB9RP/vqq2q/PpToRh4dL/FbhSZOLZ1YTotpuLHf71FGOEfgKil/4PCd3hkWe/CCeiEg==", + "license": "MIT", + "dependencies": { + "@expo/require-utils": "^57.0.6", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "semver": "^7.6.0" + } + }, + "packages/app/node_modules/@expo/plist": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.8.1.tgz", + "integrity": "sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==", + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/app/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, + "packages/app/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.86.3.tgz", + "integrity": "sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.86.3" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "packages/app/node_modules/@react-native/codegen": { + "version": "0.86.3", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.86.3.tgz", + "integrity": "sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.36.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "packages/app/node_modules/@shopify/react-native-skia": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/@shopify/react-native-skia/-/react-native-skia-2.6.2.tgz", + "integrity": "sha512-NzZ3+MRedZAUhguWw9DTCpWFd09Bq+tdGWhimGfJLGckuyoWGyimTiNTmaO2DeeivHTnGdv+eXbw7j/AV3LkRQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "canvaskit-wasm": "0.41.0", + "react-native-skia-android": "147.1.0", + "react-native-skia-apple-ios": "147.1.0", + "react-native-skia-apple-macos": "147.1.0", + "react-native-skia-apple-tvos": "147.1.0", + "react-reconciler": "0.31.0" + }, + "bin": { + "install-skia": "scripts/install-libs.js", + "setup-skia-web": "scripts/setup-canvaskit.js" + }, + "peerDependencies": { + "react": ">=19.0", + "react-native": ">=0.78", + "react-native-reanimated": ">=3.19.1" + }, + "peerDependenciesMeta": { + "react-native": { + "optional": true + }, + "react-native-reanimated": { + "optional": true + } + } + }, "packages/app/node_modules/@types/node": { "version": "22.19.21", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", @@ -37017,6 +36468,65 @@ "undici-types": "~6.21.0" } }, + "packages/app/node_modules/@typescript-eslint/scope-manager": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.2.tgz", + "integrity": "sha512-YF4wgg5iUX5Obywoac27B56FhozMNFhdJSbh11H5GBAwmBtfyRhmgTQqW9tRNNmHDvsZ2CX6UGzoz+YfYn2Leg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/visitor-keys": "8.71.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/app/node_modules/@typescript-eslint/types": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.2.tgz", + "integrity": "sha512-y5Ukl3oVp7e/VGxqIoEXoeb/Roj71PAJ4WG/N/RGj+eeDvKRLM15kGr9MijLbN0i03S52zxu31Z98E5gWChJKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/app/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.2.tgz", + "integrity": "sha512-zozlN0UA32bSG2zkKAgQyRYSbEISVoyU6vvkKYo2aSny74D8Jh4e+POkJ6Lk0dlezZi5x7TtD+88Xb06IB8nhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.71.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "packages/app/node_modules/@xmldom/xmldom": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.15.tgz", + "integrity": "sha512-/5NV/vDALVFDXgLmfsy9TRCBlKwO2LNBFzpzvb9iIj+jR+eSc6DLYYvVOdivT/jm7MtU6TebYuRmzEOI7w40UA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "packages/app/node_modules/@xterm/addon-clipboard": { "version": "0.3.0-beta.213", "resolved": "https://registry.npmjs.org/@xterm/addon-clipboard/-/addon-clipboard-0.3.0-beta.213.tgz", @@ -37118,6 +36628,131 @@ "addons/*" ] }, + "packages/app/node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.1.tgz", + "integrity": "sha512-ycduwJbvdvIMmVvlAZqGggS+pm5Eu4Bk9pcV9Sm2Z4PJNRVsKkv0g7vHj+LeuC1gHTeF67sJXFOq61IlqCa2hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-parser": "0.36.1" + } + }, + "packages/app/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "dev": true, + "license": "MIT" + }, + "packages/app/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "packages/app/node_modules/babel-preset-expo": { + "version": "57.0.16", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-57.0.16.tgz", + "integrity": "sha512-hGsVNbgxYchVyvBiFAVf+uHVMVIGObiWzAsnv8GsM/ZZRnrhGJLD8x/BLtNNycEYSIb23wPPlSqTGiw0iwwJvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.86.3", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.0", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^57.0.26", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, + "packages/app/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "packages/app/node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "packages/app/node_modules/canvaskit-wasm": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/canvaskit-wasm/-/canvaskit-wasm-0.41.0.tgz", + "integrity": "sha512-cnbL02NFB3yOYMF/MtxViZHgD1vh55Pvy+zR8q4JuFvyCPejZP3eClkt2GuZ0S7jOmGMCJXaHBasbMChbR9JZg==", + "license": "BSD-3-Clause", + "dependencies": { + "@webgpu/types": "0.1.21" + } + }, "packages/app/node_modules/dom-serializer": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-3.1.1.tgz", @@ -37239,17 +36874,757 @@ "@esbuild/win32-x64": "0.28.1" } }, - "packages/app/node_modules/expo-clipboard": { - "version": "8.0.7", - "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-8.0.7.tgz", - "integrity": "sha512-zvlfFV+wB2QQrQnHWlo0EKHAkdi2tycLtE+EXFUWTPZYkgu1XcH+aiKfd4ul7Z0SDF+1IuwoiW9AA9eO35aj3Q==", + "packages/app/node_modules/eslint-config-expo": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/eslint-config-expo/-/eslint-config-expo-57.0.2.tgz", + "integrity": "sha512-dOWkx+MWclLVnYpPPBzas4sfnPaAjk+fe/dbvJSzbWtHUR4fGGaTT/lTcOpxqhwRIlTKKBUYGKude0tcTBsZHg==", + "dev": true, "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "^8.59.0", + "@typescript-eslint/parser": "^8.59.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-expo": "^1.1.0", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react-hooks": "^7.0.0", + "globals": "^16.0.0" + }, + "peerDependencies": { + "eslint": ">=8.10" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.2.tgz", + "integrity": "sha512-K72/pvT7qpm8q3k8G5u93NCSN1RcLxX5h7Gw0bQpbMXviBHeY6Nx1WEwmk9wP+eKTSQ8ecxvcgt/ZX/rB938xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.71.2", + "@typescript-eslint/type-utils": "8.71.2", + "@typescript-eslint/utils": "8.71.2", + "@typescript-eslint/visitor-keys": "8.71.2", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.71.2", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.2.tgz", + "integrity": "sha512-cC8UaalCViJkb3rH/xLIvidEwoFRtMZMUqDjjJMGEKaTFwYRHYBcoczlEGHuvkHEO8svRDrgZ0yQgOArFmwang==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/typescript-estree": "8.71.2", + "@typescript-eslint/utils": "8.71.2", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.2.tgz", + "integrity": "sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.71.2", + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/typescript-estree": "8.71.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/parser": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.2.tgz", + "integrity": "sha512-aTtmZjp/x3gsGHkDs04/1I8kNogBJkpQaeGaN0PfiG43NzDEmW2n+OP5im9wfsvyX0yP1UZWBrAGtDBfH9jEVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.71.2", + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/typescript-estree": "8.71.2", + "@typescript-eslint/visitor-keys": "8.71.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/project-service": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.2.tgz", + "integrity": "sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.71.2", + "@typescript-eslint/types": "^8.71.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.2.tgz", + "integrity": "sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.2.tgz", + "integrity": "sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.71.2", + "@typescript-eslint/tsconfig-utils": "8.71.2", + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/visitor-keys": "8.71.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/eslint-plugin-react-hooks": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz", + "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "packages/app/node_modules/eslint-config-expo/node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/ignore": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.12.tgz", + "integrity": "sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "packages/app/node_modules/eslint-config-expo/node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "packages/app/node_modules/eslint-plugin-expo": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-expo/-/eslint-plugin-expo-1.2.1.tgz", + "integrity": "sha512-6eIogfGM7tIq169MbqJTA0iaI9h/VGujSUAy85hA3OHvYecEYM8XE9fMLd7ywnQClnVkT3JgbW8NWyhEP8g5yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "^8.59.0", + "@typescript-eslint/utils": "^8.59.0", + "eslint": "^9.24.0" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0" + }, + "peerDependencies": { + "eslint": ">=8.10" + } + }, + "packages/app/node_modules/eslint-plugin-expo/node_modules/@typescript-eslint/project-service": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.2.tgz", + "integrity": "sha512-Pd68GsLVh5ZXlcEccFPdhSOvtHZ/2WU0XsA8zmXOS3F158lVlcTLhfQ6qvtL1RzbMie0Kp8xtbVwAg4nejKPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.71.2", + "@typescript-eslint/types": "^8.71.2", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-plugin-expo/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.2.tgz", + "integrity": "sha512-jz49TAWokm/7yWD9/o837nYax9DyALxIPOImdImvVzo6canBCZYzin8zJyqNR5k1j9K1DE0bVvr0XYB+99uAdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-plugin-expo/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.2.tgz", + "integrity": "sha512-DgNOEsl4pdYzwSL+N/Cl33tX1Hlw3FvId73LnKXfq7jnrF2viOEn7X+P7RBkkSWCVm92gnWd28GIC5vJuLREeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.71.2", + "@typescript-eslint/tsconfig-utils": "8.71.2", + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/visitor-keys": "8.71.2", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-plugin-expo/node_modules/@typescript-eslint/utils": { + "version": "8.71.2", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.2.tgz", + "integrity": "sha512-RyKa1G1M9rKHDhrk+HJtiF1MvLD5Ux2JW3TSkzw+02pRALdpJb+QzG1Y5em+LvCgzGwgg8H7mBRFKljNz7ImPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.71.2", + "@typescript-eslint/types": "8.71.2", + "@typescript-eslint/typescript-estree": "8.71.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "packages/app/node_modules/eslint-plugin-expo/node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "packages/app/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "packages/app/node_modules/expo-application": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-57.0.3.tgz", + "integrity": "sha512-t/CxeLio0NjY9/cOak1tQp62/hAUjzJxmhR4rVUR7K5bb9YoEtfl1ZekTn+Iuh+dYOMYzF0l72ODMSmY3CR1NA==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-audio": { + "version": "57.0.5", + "resolved": "https://registry.npmjs.org/expo-audio/-/expo-audio-57.0.5.tgz", + "integrity": "sha512-39fX5JC5zDvELB4/eDJPj2XAYRN0W9+K2DfDWm5N3aC5WZ7HRrhupWtT6hbH09NlfYpsRSqYOwEZnocFM42ynQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "expo-asset": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/expo-build-properties": { + "version": "57.0.22", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-57.0.22.tgz", + "integrity": "sha512-A5oRf2I02XDRu2NnqKo7Au5kUu244unvyoRMUsB+xvg/BOlsR+G/oyDFGkjbda1cJbeKm9eqposIXbA2ri5UrQ==", + "license": "MIT", + "dependencies": { + "@expo/schema-utils": "^57.0.2", + "resolve-from": "^5.0.0", + "semver": "^7.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-camera": { + "version": "57.0.6", + "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-57.0.6.tgz", + "integrity": "sha512-eswB77bOzQ2OEvll/hV5VnzywaICFnYF21HIwcyokebFcSTSMfGQk8+VW06DRec9JnWuRExs0QXlfxyMPjS6KQ==", + "license": "MIT", + "dependencies": { + "barcode-detector": "^3.0.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "packages/app/node_modules/expo-crypto": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-57.0.4.tgz", + "integrity": "sha512-LqMMs/N6wvwZyw4deVmcl3AgXgqMwCVQ9WyWf2eaWyrk99TXSKk5da3QspiLOOjnn5Qv9f8C50cDNuoyLThpdw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-dev-client": { + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-57.0.20.tgz", + "integrity": "sha512-ko5FzWsUPuG4aiQfmqxQA5yAdmal6SSICB70KJLChQYzWo+XDoTpXRgEpzQSr1Ku8KyKW0lkEa48xbnKSgd1xQ==", + "license": "MIT", + "dependencies": { + "expo-dev-launcher": "~57.0.21", + "expo-dev-menu": "~57.0.20", + "expo-dev-menu-interface": "~57.0.0", + "expo-manifests": "~57.0.2", + "expo-updates-interface": "~57.0.2" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-dev-launcher": { + "version": "57.0.21", + "resolved": "https://registry.npmjs.org/expo-dev-launcher/-/expo-dev-launcher-57.0.21.tgz", + "integrity": "sha512-dXa1bhCEtSXn4y34rydBvArmoZtcLK7zY0FN3x1JFPTGh81OXUGZWhyzLCAI9nhI23L/MTy7cGCeNyeJmC1ITw==", + "license": "MIT", + "dependencies": { + "@expo/schema-utils": "^57.0.2", + "expo-dev-menu": "~57.0.20", + "expo-manifests": "~57.0.2" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/expo-dev-menu": { + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-dev-menu/-/expo-dev-menu-57.0.20.tgz", + "integrity": "sha512-xpf7Rkj++sBA285GqWVJTtl5j/TychD980GKqWA5lVFKM41+xUNmyPMOfO18heAKvX9i620ZHVoHiBGD+6pCdA==", + "license": "MIT", + "dependencies": { + "expo-dev-menu-interface": "~57.0.0" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/expo-dev-menu-interface": { + "version": "57.0.0", + "resolved": "https://registry.npmjs.org/expo-dev-menu-interface/-/expo-dev-menu-interface-57.0.0.tgz", + "integrity": "sha512-F47VdzOHYc19FhI/jBgctpO8a5UskTIxG6a1E5t3W5gF8VImuvBQffdXXfLHhsuCl7dS3v3U0R45cleeVXO1Zg==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-document-picker": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-document-picker/-/expo-document-picker-57.0.3.tgz", + "integrity": "sha512-XlxdZ0zzv44JRD8O15DISgIO8FTaZ581oc4kQp6MJoR7vdahjcY+2qCuDt5k1J8/lc0YR+bXon/v81norciuxw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-haptics": { + "version": "57.0.3", + "resolved": "https://registry.npmjs.org/expo-haptics/-/expo-haptics-57.0.3.tgz", + "integrity": "sha512-qucUXtwtJdtECKSQK5D6TQBc/0SxKj7s5wQ4mrfSxhZsHrS9a4rcxINl/gbruMaY9spTXStco32ST4pV0vXmxw==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-image": { + "version": "57.0.5", + "resolved": "https://registry.npmjs.org/expo-image/-/expo-image-57.0.5.tgz", + "integrity": "sha512-jOm5lofaIKXhQ7i0Hz3I5JuNULw/aghmpIPZXddwQcEtw8+wUhlozq3M7LbsOrcsBEapcG4jFs85DsfuFoz1tQ==", + "license": "MIT", + "dependencies": { + "sf-symbols-typescript": "^2.2.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "packages/app/node_modules/expo-image-loader": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-57.0.1.tgz", + "integrity": "sha512-uhrZKLT/cTl2mXyR28kPpVkS5O+PK9N1QA/07IFM4f5T4g0lTW1JHT3NEWwEEsGFldPmVX4j7LwUVVZxE+woug==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-image-manipulator": { + "version": "57.0.21", + "resolved": "https://registry.npmjs.org/expo-image-manipulator/-/expo-image-manipulator-57.0.21.tgz", + "integrity": "sha512-NZeNvZxBNf/PK97Df5zORmtqRR/LovkA+lHdRLm1IJFiVKjs4xr+Ib6/jWhDxn04VOX3TJswCQyu4SCxkgMe4Q==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~57.0.1" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-image-picker": { + "version": "57.0.20", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-57.0.20.tgz", + "integrity": "sha512-plgcGuMZMWqDchjXQW6S/WepYLB5KqfbZOzwC6xe0+j5IhY4ipvVuRZcXeP/0NgKgU0Jiu/XoTK4Bi8crtZ+sQ==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~57.0.1" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-json-utils": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-57.0.2.tgz", + "integrity": "sha512-9kYZECLKE3pYZQs+kt3+ggY83Lfryog9/UEo3HJKGcHUZeKKtlFBIPFjI4LzREubsvjP7AsvG0FdEX9EquIoAQ==", + "license": "MIT" + }, + "packages/app/node_modules/expo-localization": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-localization/-/expo-localization-57.0.2.tgz", + "integrity": "sha512-sIKYH3Ivddoge568WY6j+Kp2MAAZzWWqEnY2bokLkJFwX366tGL1mEnoY2WUi/qHatFFPop2yqDdurzbhnnimQ==", + "license": "MIT", + "dependencies": { + "rtl-detect": "^1.0.2" + }, + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, + "packages/app/node_modules/expo-manifests": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-57.0.2.tgz", + "integrity": "sha512-pPIIcKR73OShwlWMg8H90WRzKUd2krDdKlKAwuQV1FtUwE7H3hQEFw0ePFQY9yFoGMF/77ryYwNKfI5umMcCog==", + "license": "MIT", + "dependencies": { + "expo-json-utils": "~57.0.2" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-notifications": { + "version": "57.0.23", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-57.0.23.tgz", + "integrity": "sha512-KdHROY5tvbzlDJImJKF91F8GRpV4hP+RLPC7NJgiFNyzb0clETpV0hJNdbFrfyubZf+cqx88+WuwFsH9Yl+kzg==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.11.6", + "abort-controller": "^3.0.0", + "badgin": "^1.1.5", + "expo-application": "~57.0.3", + "expo-constants": "~57.0.22" + }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, + "packages/app/node_modules/expo-sharing": { + "version": "57.0.23", + "resolved": "https://registry.npmjs.org/expo-sharing/-/expo-sharing-57.0.23.tgz", + "integrity": "sha512-fN+jrqoWwOpIo+X4utiu/ayCWym23DMgvrTJUHoopkBeO6rEa79ZY4f6ApOlRxvEx2NgQgJEQX+cbPJrjOSRog==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "^57.0.10", + "@expo/config-types": "^57.0.2", + "@expo/plist": "^0.8.1" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/expo-splash-screen": { + "version": "57.0.10", + "resolved": "https://registry.npmjs.org/expo-splash-screen/-/expo-splash-screen-57.0.10.tgz", + "integrity": "sha512-W7++tMiyVMviWPTvaTXKpcOwwu5SbriwA2n0ewEhC+ic1LFaUNTUXiIXr95MVMSHaLRgtIG9dGyCTCb+NkekkA==", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "~57.0.10", + "@expo/image-utils": "^0.11.6", + "xml2js": "0.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/expo-sqlite": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-sqlite/-/expo-sqlite-57.0.4.tgz", + "integrity": "sha512-3N/bnDx4+kWEC9GABxKPLe/6RHTZJR/7DNT5tz/cYi8f7emign3ooavXnJn0+JPBA0JhHmsdDPrmC+CtT86Jzg==", + "license": "MIT", + "dependencies": { + "await-lock": "^2.2.2" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/expo-system-ui": { + "version": "57.0.4", + "resolved": "https://registry.npmjs.org/expo-system-ui/-/expo-system-ui-57.0.4.tgz", + "integrity": "sha512-z//rxQJzhTNA1PcKrUtWmrd21jAS3nEDu1b0n8B/7LTTR933OcsZYP1HnbaZifuo2ZH/h7nce2Ow61WZ1Ig2bg==", + "license": "MIT", + "dependencies": { + "@react-native/normalize-colors": "0.86.3", + "debug": "^4.3.2" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*", + "react-native-web": "*" + }, + "peerDependenciesMeta": { + "react-native-web": { + "optional": true + } + } + }, + "packages/app/node_modules/expo-updates-interface": { + "version": "57.0.2", + "resolved": "https://registry.npmjs.org/expo-updates-interface/-/expo-updates-interface-57.0.2.tgz", + "integrity": "sha512-x3SA5toiHZEkW+5oeNdUM1Rvt6M3ExegQsSwS3Z1+S9gn9utGYTGBkb8MBQivhjIZiRlQYDIhauxA8kySQEWtQ==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, + "packages/app/node_modules/getenv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", + "integrity": "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "packages/app/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/app/node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/app/node_modules/hermes-estree": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.0.tgz", + "integrity": "sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==", + "dev": true, + "license": "MIT" + }, + "packages/app/node_modules/hermes-parser": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.0.tgz", + "integrity": "sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.36.0" + } + }, "packages/app/node_modules/htmlparser2": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-12.0.0.tgz", @@ -37327,6 +37702,46 @@ "node": ">=22.0.0" } }, + "packages/app/node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/app/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/app/node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "packages/app/node_modules/path-to-regexp": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", @@ -37365,6 +37780,35 @@ "react-native-reanimated": ">=3.0.0" } }, + "packages/app/node_modules/react-native-screens": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.26.2.tgz", + "integrity": "sha512-2XnWsZToKj76trGtEZzx5ELD/qOICFEprEeUntImmitQFVUkea27fiWdUSITArI356Y1qynpXZINW+Unbhky/A==", + "license": "MIT", + "dependencies": { + "react-freeze": "^1.0.0", + "warn-once": "^0.1.0" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "packages/app/node_modules/react-native-svg": { + "version": "15.15.4", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.4.tgz", + "integrity": "sha512-boT/vIRgj6zZKBpfTPJJiYWMbZE9duBMOwPK6kCSTgxsS947IFMOq9OgIFkpWZTB7t229H24pDRkh3W9ZK/J1A==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "packages/app/node_modules/turndown": { "version": "7.2.4", "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.4.tgz", @@ -37467,6 +37911,15 @@ } } }, + "packages/app/node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, "packages/cli": { "name": "@getpaseo/cli", "version": "0.12.0", @@ -37993,6 +38446,20 @@ "react-native": "*" } }, + "packages/expo-two-way-audio/node_modules/@expo/code-signing-certificates": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.7.tgz", + "integrity": "sha512-zP0tnfqrFFRL8INtOaQ6XwEYfdIpIH9vrEo7y0bHQGQa50z4/QWXE5CI4nRUHxqFW4MVWOwXFg1hom1aAZHNkQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "node-forge": "^1.4.0" + }, + "engines": { + "node": ">=22.13.0" + } + }, "packages/expo-two-way-audio/node_modules/@expo/config": { "version": "12.0.13", "resolved": "https://registry.npmjs.org/@expo/config/-/config-12.0.13.tgz", @@ -38076,6 +38543,223 @@ "@babel/highlight": "^7.10.4" } }, + "packages/expo-two-way-audio/node_modules/@expo/devtools": { + "version": "58.0.2", + "resolved": "https://registry.npmjs.org/@expo/devtools/-/devtools-58.0.2.tgz", + "integrity": "sha512-WBj/K+vv8JPSmY70ennL04YYOHkpEsGGkfuVY9lfv4XO7Qhbt5qz4q6W7maME194I5oGcimRMigUFfWNkBe90w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^4.1.2" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + }, + "react": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/dom-webview": { + "version": "58.0.2", + "resolved": "https://registry.npmjs.org/@expo/dom-webview/-/dom-webview-58.0.2.tgz", + "integrity": "sha512-bLkREoP7qL3rEuzxP60xG+TjdPoGjbnZfxkvYo5imJxGWfKMOf7x962W06Pu+WWAr4gcDRk16iA+Clg8D0zjCg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/env": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/@expo/env/-/env-2.5.2.tgz", + "integrity": "sha512-z8kCvBVJpd2S20a+Ab1otQgz8sJLeR7CXDTsuAMcNbYFsK10Fdhfb7rx9Ys1vvlbijnY55eZhQvJACajc1IjBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^4.0.0", + "debug": "^4.3.4", + "getenv": "^2.0.0" + }, + "engines": { + "node": ">=20.12.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/fingerprint": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@expo/fingerprint/-/fingerprint-0.21.5.tgz", + "integrity": "sha512-4ngc+aPgMK56sYc47tfabmoaNdP7OvPBOH7QPgN3riSYM0Ev+KwsGRDius5jBBwjCI9ADp7IpjJEK9xlRYjjvA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/env": "^2.5.2", + "@expo/spawn-async": "^1.8.0", + "arg": "^5.0.2", + "chalk": "^4.1.2", + "debug": "^4.3.4", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "ignore": "^5.3.1", + "minimatch": "^10.2.2", + "resolve-from": "^5.0.0", + "semver": "^7.7.4" + }, + "bin": { + "fingerprint": "bin/cli.js" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/fingerprint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/image-utils": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/@expo/image-utils/-/image-utils-0.12.5.tgz", + "integrity": "sha512-nsFYd7GfDdwZa+S+p+EkVCkh7UKKNf0kfUXDQ53HbyMmNFD3psb5JYwU/2N+uZG5wOEfKGfQ5u7pk/wn2gMlBA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/require-utils": "^58.0.4", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "getenv": "^2.0.0", + "jimp-compact": "0.16.1", + "parse-png": "^2.1.0", + "semver": "^7.7.4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/image-utils/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@expo/inline-modules/-/inline-modules-0.2.6.tgz", + "integrity": "sha512-S8PK3wx6ogwunoQ7pqdPbklQGtXloeWTAOzWJ9yIL7xHFxvnI/Ryj0phA3KEGCMlaKZjaCP1h/3s7n/ueErRgQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-plugins": "~58.0.9" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules/node_modules/@expo/config-plugins": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-58.0.9.tgz", + "integrity": "sha512-HyP7V1QgDxeHcOEh4qQH7cfK7cI7wNp0y9lszAu98SRYCshhDbwB9gWpFfnpX1GQUtgiqG4Hvgh1z3ntcGwAjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-types": "^58.0.3", + "@expo/json-file": "~11.2.1", + "@expo/plist": "^0.10.1", + "@expo/require-utils": "^58.0.4", + "@expo/sdk-runtime-versions": "^1.0.1", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.7.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules/node_modules/@expo/config-types": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-58.0.3.tgz", + "integrity": "sha512-wyfrwkTT/hQHzwyqkXkngKxoOa8L6ovsTP4h/UukS1mTmssee5et6HOPoN5RtawdJPnm5JO28f//C/wXlpka8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules/node_modules/@expo/plist": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.10.1.tgz", + "integrity": "sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/inline-modules/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "packages/expo-two-way-audio/node_modules/@expo/json-file": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-10.2.0.tgz", @@ -38087,6 +38771,424 @@ "json5": "^2.2.3" } }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider": { + "version": "58.0.6", + "resolved": "https://registry.npmjs.org/@expo/local-build-cache-provider/-/local-build-cache-provider-58.0.6.tgz", + "integrity": "sha512-AJk3pslFNlwRMbUbfvxhu6CPA9U7A+JPb88VS/uWkG/S/QMJL90Iw4sPVfG4BOKfRUNkB8ipl432Dr4txjSMKw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config": "~58.0.6", + "chalk": "^4.1.2" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/config": { + "version": "58.0.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-58.0.6.tgz", + "integrity": "sha512-PT1qv4s/R5A/NxXb4efGlFsYF5Consi7F8xSsJBAN090EGDr6U1EDQGOijFqzDc3JA2epD8zjKLJLOVB9YOewg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-plugins": "~58.0.9", + "@expo/config-types": "^58.0.3", + "@expo/json-file": "^11.2.1", + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.7.4", + "slugify": "^1.3.4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/config-plugins": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-58.0.9.tgz", + "integrity": "sha512-HyP7V1QgDxeHcOEh4qQH7cfK7cI7wNp0y9lszAu98SRYCshhDbwB9gWpFfnpX1GQUtgiqG4Hvgh1z3ntcGwAjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-types": "^58.0.3", + "@expo/json-file": "~11.2.1", + "@expo/plist": "^0.10.1", + "@expo/require-utils": "^58.0.4", + "@expo/sdk-runtime-versions": "^1.0.1", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.7.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/config-types": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-58.0.3.tgz", + "integrity": "sha512-wyfrwkTT/hQHzwyqkXkngKxoOa8L6ovsTP4h/UukS1mTmssee5et6HOPoN5RtawdJPnm5JO28f//C/wXlpka8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/plist": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.10.1.tgz", + "integrity": "sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/local-build-cache-provider/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/log-box": { + "version": "58.0.12", + "resolved": "https://registry.npmjs.org/@expo/log-box/-/log-box-58.0.12.tgz", + "integrity": "sha512-IzDYoFY2iUsmSDvl1V7YUM7UkCPDyMVS4e4a38c2LnFc1A3WGMUiQh+vsHLYTPKjIelu4r7/u4V7Gxtfa0oJgA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/dom-webview": "^58.0.2", + "@expo/log-box-utils": "^58.0.2", + "anser": "^1.4.9", + "stacktrace-parser": "^0.1.10" + }, + "peerDependencies": { + "@expo/dom-webview": "^58.0.2", + "expo": "*", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro": { + "version": "58.0.0", + "resolved": "https://registry.npmjs.org/@expo/metro/-/metro-58.0.0.tgz", + "integrity": "sha512-PMD640ihB0C3Oqm0AnDVJ/8qF2cKbRUEqGuSOr4tM/OTb9ktxsQqsiSSSeaOEgdCZBq20AxRS0d6WHNhhH2P+g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "metro": "0.87.1", + "metro-babel-transformer": "0.87.1", + "metro-cache": "0.87.1", + "metro-cache-key": "0.87.1", + "metro-config": "0.87.1", + "metro-core": "0.87.1", + "metro-file-map": "0.87.1", + "metro-minify-terser": "0.87.1", + "metro-resolver": "0.87.1", + "metro-runtime": "0.87.1", + "metro-source-map": "0.87.1", + "metro-symbolicate": "0.87.1", + "metro-transform-plugins": "0.87.1", + "metro-transform-worker": "0.87.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config": { + "version": "58.0.14", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-58.0.14.tgz", + "integrity": "sha512-UDUMAJwYGEzaB26ejMLG/IOVzwKDbHzoODBf3FZeRS94kk9jDf1dWE1VMX6bLBLoiflxXwqrMWiH0Fvz3gZ9YQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.20.0", + "@babel/generator": "^7.20.5", + "@expo/config": "~58.0.6", + "@expo/env": "~2.5.2", + "@expo/json-file": "~11.2.1", + "@expo/metro": "~58.0.0", + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "@expo/spawn-async": "^1.8.0", + "@jridgewell/gen-mapping": "^0.3.13", + "@jridgewell/remapping": "^2.3.5", + "@jridgewell/sourcemap-codec": "^1.5.5", + "@jridgewell/trace-mapping": "^0.3.31", + "@react-native/js-polyfills": "0.88.0", + "2g": "^1.0.1", + "browserslist": "^4.25.0", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "hermes-parser": "^0.36.0", + "jsc-safe-url": "^0.2.4", + "lightningcss": "^1.30.1", + "noxcturnal": "^0.1.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.23", + "resolve-from": "^5.0.0" + }, + "peerDependencies": { + "expo": "*" + }, + "peerDependenciesMeta": { + "expo": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/config": { + "version": "58.0.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-58.0.6.tgz", + "integrity": "sha512-PT1qv4s/R5A/NxXb4efGlFsYF5Consi7F8xSsJBAN090EGDr6U1EDQGOijFqzDc3JA2epD8zjKLJLOVB9YOewg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-plugins": "~58.0.9", + "@expo/config-types": "^58.0.3", + "@expo/json-file": "^11.2.1", + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.7.4", + "slugify": "^1.3.4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/config-plugins": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-58.0.9.tgz", + "integrity": "sha512-HyP7V1QgDxeHcOEh4qQH7cfK7cI7wNp0y9lszAu98SRYCshhDbwB9gWpFfnpX1GQUtgiqG4Hvgh1z3ntcGwAjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-types": "^58.0.3", + "@expo/json-file": "~11.2.1", + "@expo/plist": "^0.10.1", + "@expo/require-utils": "^58.0.4", + "@expo/sdk-runtime-versions": "^1.0.1", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.7.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/config-types": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-58.0.3.tgz", + "integrity": "sha512-wyfrwkTT/hQHzwyqkXkngKxoOa8L6ovsTP4h/UukS1mTmssee5et6HOPoN5RtawdJPnm5JO28f//C/wXlpka8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/plist": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.10.1.tgz", + "integrity": "sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/2g": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/2g/-/2g-1.0.1.tgz", + "integrity": "sha512-+uViadKOS/wwR4pFu5g8TPn3QHpKqoX19JHCnp8k/3cLpImdcXozwvZA6Q/5PeW3AcU8neL8faaMidBcv7o8CA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "2g": "bin/cli.js" + }, + "peerDependencies": { + "typescript": ">=5.8.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-config/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.36.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-file-map": { + "version": "58.0.5", + "resolved": "https://registry.npmjs.org/@expo/metro-file-map/-/metro-file-map-58.0.5.tgz", + "integrity": "sha512-Y2w8qKklLffZie28In4WF6f6e8nIJOhU0mZ5UaQdCiITVQm2a5teNdIDudEPkBsh8ItlvyHZt9n42PN2onRbkQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "2g": "^1.0.1", + "debug": "^4.3.4", + "fb-watchman": "^2.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "walker": "^1.0.8" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/metro-file-map/node_modules/2g": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/2g/-/2g-1.0.1.tgz", + "integrity": "sha512-+uViadKOS/wwR4pFu5g8TPn3QHpKqoX19JHCnp8k/3cLpImdcXozwvZA6Q/5PeW3AcU8neL8faaMidBcv7o8CA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "2g": "bin/cli.js" + }, + "peerDependencies": { + "typescript": ">=5.8.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/osascript": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/@expo/osascript/-/osascript-2.8.1.tgz", + "integrity": "sha512-SCi+6q6uOkGhiAn6AIP/OPFgaIq/iKD2oYpnAOg2rShHStJ8ey7wyT127RbOaZXmlcY/62rHOX1WiiMnD8u/BA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/spawn-async": "^1.8.0" + }, + "engines": { + "node": ">=12" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/package-manager": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@expo/package-manager/-/package-manager-1.14.2.tgz", + "integrity": "sha512-sftl0eRVVCarI6grMdjAB3jX2pX1Mt3cdSnajlXS4QyeDkaKRM/ntBy6dcagj1VL0+cEfEqctlyvinmlZdNubg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/json-file": "^11.2.1", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.0.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "resolve-workspace-root": "^2.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/package-manager/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, "packages/expo-two-way-audio/node_modules/@expo/plist": { "version": "0.4.9", "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.4.9.tgz", @@ -38099,6 +39201,153 @@ "xmlbuilder": "^15.1.1" } }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config": { + "version": "58.0.14", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-58.0.14.tgz", + "integrity": "sha512-2wVzVDfXjRB3LzUbW5shOM/A+6eUUCfR+2bpZiWRBBZBtZP2HA5Zq1YgCio1tDqMGAHf2NQQDhvy/Rz1U6aC3A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config": "~58.0.6", + "@expo/config-plugins": "~58.0.9", + "@expo/config-types": "^58.0.3", + "@expo/image-utils": "^0.12.5", + "@expo/json-file": "^11.2.1", + "@react-native/normalize-colors": "0.88.0", + "debug": "^4.3.1", + "expo-modules-autolinking": "~58.0.13", + "resolve-from": "^5.0.0", + "semver": "^7.7.4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/config": { + "version": "58.0.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-58.0.6.tgz", + "integrity": "sha512-PT1qv4s/R5A/NxXb4efGlFsYF5Consi7F8xSsJBAN090EGDr6U1EDQGOijFqzDc3JA2epD8zjKLJLOVB9YOewg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-plugins": "~58.0.9", + "@expo/config-types": "^58.0.3", + "@expo/json-file": "^11.2.1", + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.7.4", + "slugify": "^1.3.4" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/config-plugins": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-58.0.9.tgz", + "integrity": "sha512-HyP7V1QgDxeHcOEh4qQH7cfK7cI7wNp0y9lszAu98SRYCshhDbwB9gWpFfnpX1GQUtgiqG4Hvgh1z3ntcGwAjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-types": "^58.0.3", + "@expo/json-file": "~11.2.1", + "@expo/plist": "^0.10.1", + "@expo/require-utils": "^58.0.4", + "@expo/sdk-runtime-versions": "^1.0.1", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.7.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/config-types": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-58.0.3.tgz", + "integrity": "sha512-wyfrwkTT/hQHzwyqkXkngKxoOa8L6ovsTP4h/UukS1mTmssee5et6HOPoN5RtawdJPnm5JO28f//C/wXlpka8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/plist": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.10.1.tgz", + "integrity": "sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/expo-two-way-audio/node_modules/@expo/prebuild-config/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@expo/schema-utils": { + "version": "58.0.2", + "resolved": "https://registry.npmjs.org/@expo/schema-utils/-/schema-utils-58.0.2.tgz", + "integrity": "sha512-w28y8SG+5ZTdDdmH2ZnCQk9wHVwGzI9NqX5V4urJUFEnxbm7I129fJRkb8RIAJmMA1WKU5h3ONmranV473uaXQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/@expo/sdk-runtime-versions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.1.tgz", + "integrity": "sha512-kvisefkhxu8Fm/4M8G6DEqUaigrXfrSOm2lFw7hsk/nq0zchcp6B4wSk8rlheHY8FRi5iHxKtoVMGY/3M6h04A==", + "dev": true, + "license": "MIT" + }, + "packages/expo-two-way-audio/node_modules/@expo/spawn-async": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@expo/spawn-async/-/spawn-async-1.8.0.tgz", + "integrity": "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6" + }, + "engines": { + "node": ">=12" + } + }, "packages/expo-two-way-audio/node_modules/@jest/schemas": { "version": "30.4.1", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.4.1.tgz", @@ -38112,6 +39361,312 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "packages/expo-two-way-audio/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.88.0.tgz", + "integrity": "sha512-leGEnCcS7Q0hTxvzvhNtr8zGQpI1gfWqXjzC4UedsFmNMv6kIo4s70o0XbtM30ZXbpfWe4BcSC8NKWuak5sI4A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.29.0", + "@react-native/codegen": "0.88.0" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/babel-preset": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.88.0.tgz", + "integrity": "sha512-iMfAHhFGNegnReSY6CYaWHncvyDwHq8olRs0zp9nRRApMAoCiLyfo1dwL/f39qt/MreD6xIqUs9SrTPYWobY6g==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@react-native/babel-plugin-codegen": "0.88.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "flow-parser": "0.327.0", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/babel-preset/node_modules/flow-parser": { + "version": "0.327.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.327.0.tgz", + "integrity": "sha512-/MYZ5hXWf5ozpbdfUDmazMgQXviLxWEiRLH3MppEGDdW0itRVqmB5UaU7QX+SBCDNiq+gEesSVn8nlxmPDyDkw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "flow-estree": "0.327.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/codegen": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.88.0.tgz", + "integrity": "sha512-SAGg+XfzsrPiYTscbKa9bo2/H2ei2TjyxW8RTMq2Ps661kRK3AnmpMGVfrEFshEMr3FGEbuQIvj86X98kaXlRA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "flow-parser": "0.327.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/codegen/node_modules/flow-parser": { + "version": "0.327.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.327.0.tgz", + "integrity": "sha512-/MYZ5hXWf5ozpbdfUDmazMgQXviLxWEiRLH3MppEGDdW0itRVqmB5UaU7QX+SBCDNiq+gEesSVn8nlxmPDyDkw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-estree": "0.327.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/community-cli-plugin": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.88.0.tgz", + "integrity": "sha512-WrQdXbjVt1gwAay8ZzYtpOi9ly99ksJ0VMYFdVcMe6nq3vtiRgqKRpHgCdN6ySIbtr5o+aJ+Vr7OTDY98ec/Ow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@react-native/asset-utils": "0.88.0", + "@react-native/dev-middleware": "0.88.0", + "commander": "^12.0.0", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.87.1", + "semver": "^7.1.3" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.88.0" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/debugger-frontend": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.88.0.tgz", + "integrity": "sha512-v5cnBaaWhDRPcQv8EC20zj53jOAKH7u2wnzzXS4JTNu+diPC+cA2+kC7rq3eKI5vGhlAcG2kDPoViRuC0AY0oA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/debugger-shell": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.88.0.tgz", + "integrity": "sha512-p82zT8ZKNx7nIm/8zf8pi55sxm5KQBm8td47kzoJysTdqHLyPsRMUvDXtvCJIWadHSv7RJ6t/yiCc+IoImLBtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/dev-middleware": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.88.0.tgz", + "integrity": "sha512-sHLxVHOwfkF672ZzMepNh4d3IKbrZy3qXDKWSwN5LC5VJkzzZ5FdmSPP4N/CCn2pcKJ4oSqvojXwN4De3Xk92A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.88.0", + "@react-native/debugger-shell": "0.88.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^8.4.2", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/gradle-plugin": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.88.0.tgz", + "integrity": "sha512-4jPSKslOfJj8NKY/jv9qmWkxZYmqPyamoS3Vs0JOFxw9t4PM6L/ea0fUsjNV0LxC9zJlvWilPJOCTOf7h8wlyw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/js-polyfills": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.88.0.tgz", + "integrity": "sha512-Iq6v4+EWdOLv0M1+BpADQJBVfInl6FkABXCIBSi0FbvHahEYT+Y4UJ7Cm96p18gbEN1VKzqz3nbBbwLA6bx0rQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/metro-babel-transformer": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.88.0.tgz", + "integrity": "sha512-xsUfzXrqKXeD7sBja7hkyBG32AGIwWJ3IEZ+UcNMRTR/sucnXXZ6Do40qXoeY52YC8b9//J+p51JIp2CC0DZKA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@react-native/babel-preset": "0.88.0", + "flow-parser": "0.327.0", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/metro-babel-transformer/node_modules/flow-parser": { + "version": "0.327.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.327.0.tgz", + "integrity": "sha512-/MYZ5hXWf5ozpbdfUDmazMgQXviLxWEiRLH3MppEGDdW0itRVqmB5UaU7QX+SBCDNiq+gEesSVn8nlxmPDyDkw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "flow-estree": "0.327.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/metro-config": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.88.0.tgz", + "integrity": "sha512-iPV2HNXlPs7xQDBJJGIjkH0x2psZwJeRIEpfSqxgqLaO5eEfE2Ccicfz2OBHBcIC5jKGGa4IoI/e26zMNDuTMQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@react-native/js-polyfills": "0.88.0", + "@react-native/metro-babel-transformer": "0.88.0", + "metro-config": "^0.87.1", + "metro-runtime": "^0.87.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/@react-native/normalize-colors": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.88.0.tgz", + "integrity": "sha512-eZCu3tGAQCfvMCPQJVY4dmoMX8ZZYBvqIGHX7lwOYyzNK+Dl8e5ky7ZoXub1Rq75oSrQXNNmSP2CDjNNXXZpFQ==", + "dev": true, + "license": "MIT", + "peer": true + }, "packages/expo-two-way-audio/node_modules/@sinclair/typebox": { "version": "0.34.49", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", @@ -38190,6 +39745,17 @@ "node": ">=10.0.0" } }, + "packages/expo-two-way-audio/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14" + } + }, "packages/expo-two-way-audio/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -38203,6 +39769,44 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "packages/expo-two-way-audio/node_modules/babel-plugin-react-native-web": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.21.4.tgz", + "integrity": "sha512-FSclsDTGi5EcvpbW3TM7s8GLWwQqo5wI9zQqJr2m0IoJRenSkp1+bVvdeZXTNznI5Ms9Bry7DLBR+C5Shb9gtw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.36.1.tgz", + "integrity": "sha512-ycduwJbvdvIMmVvlAZqGggS+pm5Eu4Bk9pcV9Sm2Z4PJNRVsKkv0g7vHj+LeuC1gHTeF67sJXFOq61IlqCa2hA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-parser": "0.36.1" + } + }, + "packages/expo-two-way-audio/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.36.1.tgz", + "integrity": "sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.36.1.tgz", + "integrity": "sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.36.1" + } + }, "packages/expo-two-way-audio/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -38226,6 +39830,39 @@ "node": "18 || 20 || >=22" } }, + "packages/expo-two-way-audio/node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "packages/expo-two-way-audio/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT", + "peer": true + }, "packages/expo-two-way-audio/node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", @@ -38236,6 +39873,32 @@ "node": ">=18" } }, + "packages/expo-two-way-audio/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "packages/expo-two-way-audio/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.0" + } + }, "packages/expo-two-way-audio/node_modules/eslint-config-prettier": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.2.tgz", @@ -38493,6 +40156,97 @@ "url": "https://opencollective.com/eslint" } }, + "packages/expo-two-way-audio/node_modules/expo-asset": { + "version": "58.0.16", + "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-58.0.16.tgz", + "integrity": "sha512-beR3uusLA+rFo+6Ug0L7FPR4b6y/37VwtYW2Jig/i+3Co+oyYCTnvVuFPWhb05W9TOZRxdHUEI569fVKIgtYAA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/image-utils": "^0.12.5", + "expo-constants": "~58.0.12" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/expo-constants": { + "version": "58.0.12", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-58.0.12.tgz", + "integrity": "sha512-d3/dsps32nU4m6YJQbXQ1dIfn58GxfmJjTnZ0WtnhdSHTdG/oVsOakLqYRlX/FaLUKkQOSHXMf7hyCx+2a/HSQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/env": "~2.5.2", + "@expo/require-utils": "^58.0.4" + }, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/expo-constants/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-file-system": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-58.0.9.tgz", + "integrity": "sha512-JT0km3Wa+wDz/7Rli8ifreoMnmk68ulf/uaWzRA26xm/4K+jGTY+cDhnboRmpmXUCBkED6uqxWmNoXjaVU9VUw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "expo": "*", + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/expo-font": { + "version": "58.0.8", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-58.0.8.tgz", + "integrity": "sha512-i9HKj/ljdmmjLamYQEkI4wXJB9+ap7AG5CpCqK/bgwwy45y5T8+1lpNbYgRXE7aQgmDjPpzd09wX6dOZkHfrxg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/expo-keep-awake": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-58.0.3.tgz", + "integrity": "sha512-wLRF+XeVsD/Rt/ZyX+A0mk1brdf8vefWizNAPzqV5eOCgkj23LCRZdN8gUi5X8UwyR8UJ7Y7Dzdz4YDGB/4c9Q==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "expo": "*", + "react": "*" + } + }, "packages/expo-two-way-audio/node_modules/expo-module-scripts": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/expo-module-scripts/-/expo-module-scripts-5.0.8.tgz", @@ -38524,6 +40278,175 @@ "expo-module": "bin/expo-module.js" } }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/config-plugins": { + "version": "58.0.9", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-58.0.9.tgz", + "integrity": "sha512-HyP7V1QgDxeHcOEh4qQH7cfK7cI7wNp0y9lszAu98SRYCshhDbwB9gWpFfnpX1GQUtgiqG4Hvgh1z3ntcGwAjw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-types": "^58.0.3", + "@expo/json-file": "~11.2.1", + "@expo/plist": "^0.10.1", + "@expo/require-utils": "^58.0.4", + "@expo/sdk-runtime-versions": "^1.0.1", + "chalk": "^4.1.2", + "debug": "^4.3.5", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "semver": "^7.7.4", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/config-plugins/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/config-plugins/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/config-types": { + "version": "58.0.3", + "resolved": "https://registry.npmjs.org/@expo/config-types/-/config-types-58.0.3.tgz", + "integrity": "sha512-wyfrwkTT/hQHzwyqkXkngKxoOa8L6ovsTP4h/UukS1mTmssee5et6HOPoN5RtawdJPnm5JO28f//C/wXlpka8Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/metro-runtime": { + "version": "58.0.14", + "resolved": "https://registry.npmjs.org/@expo/metro-runtime/-/metro-runtime-58.0.14.tgz", + "integrity": "sha512-IIvTo+RpN5jZVuYspQdECsxQ03VGWjZnGS6wtr9U7DERBpykUe+ZSHDZ1hsrvQ7HAucsVoKr9np0xAscGEuXtg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@expo/log-box": "^58.0.12", + "anser": "^1.4.9", + "pretty-format": "^29.7.0", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0" + }, + "peerDependencies": { + "@expo/log-box": "^58.0.12", + "expo": "*", + "react": "*", + "react-dom": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/metro-runtime/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@expo/plist": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@expo/plist/-/plist-0.10.1.tgz", + "integrity": "sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@react-native/virtualized-lists": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.88.0.tgz", + "integrity": "sha512-zpZIOAbobdS93edwHkNUdGDzvElNeQJqukRERRPns3/ucPvuMd2G4fYpmVJSVjhxtGCcLLB1PFndLYYfwaYoBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "0.88.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@sinclair/typebox": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.12.tgz", + "integrity": "sha512-hhyNJ+nbR6ZR7pToHvllEFun9TL0sbL+tk/ON75lo+Xas054uez98qRbsuNt7MBCyZKK4+8Yli/OAGZhmfBZ/g==", + "dev": true, + "license": "MIT", + "peer": true + }, "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@testing-library/react-native": { "version": "13.3.3", "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.3.3.tgz", @@ -38551,6 +40474,406 @@ } } }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo": { + "version": "58.0.14", + "resolved": "https://registry.npmjs.org/expo/-/expo-58.0.14.tgz", + "integrity": "sha512-M05O++KRgG4NA6kQ9AP60kbN8xqHJ6S8uTXdtkeiwcGVIYzdu2kaUXJyraVturvePO/Mf4PWa0C9+JggrHITwA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.20.0", + "@expo/cli": "^58.1.11", + "@expo/config": "~58.0.6", + "@expo/config-plugins": "~58.0.9", + "@expo/devtools": "~58.0.2", + "@expo/dom-webview": "~58.0.2", + "@expo/fingerprint": "^0.21.5", + "@expo/local-build-cache-provider": "^58.0.6", + "@expo/log-box": "^58.0.12", + "@expo/log-box-utils": "^58.0.2", + "@expo/metro": "~58.0.0", + "@expo/metro-config": "~58.0.14", + "@ungap/structured-clone": "^1.3.0", + "babel-preset-expo": "~58.0.17", + "expo-asset": "~58.0.16", + "expo-constants": "~58.0.12", + "expo-file-system": "~58.0.9", + "expo-font": "~58.0.8", + "expo-keep-awake": "~58.0.3", + "expo-modules-autolinking": "~58.0.13", + "expo-modules-core": "~58.0.22", + "pretty-format": "^29.7.0", + "react-refresh": "^0.14.2", + "whatwg-url-minimum": "^0.2.0" + }, + "bin": { + "expo": "bin/cli", + "expo-modules-autolinking": "bin/autolinking", + "fingerprint": "bin/fingerprint" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0" + }, + "peerDependencies": { + "@expo/dom-webview": "*", + "@expo/metro-runtime": "*", + "react": "*", + "react-dom": "*", + "react-native": "*", + "react-native-web": "*", + "react-native-webview": "*" + }, + "peerDependenciesMeta": { + "@expo/dom-webview": { + "optional": true + }, + "@expo/metro-runtime": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-native-web": { + "optional": true + }, + "react-native-webview": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo-modules-core": { + "version": "58.0.22", + "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-58.0.22.tgz", + "integrity": "sha512-T3YJYziFkF4JlGDpX4zCl91oIxz1Skq5sp1LFVO+GL/BARSIXk013QWGdRZrvt+wMxoVaql5dpOdPdP5q2+0jQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "expo-modules-jsi": "~58.0.15", + "expo-modules-macros": "0.20.0", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "react": "*", + "react-native": "*", + "react-native-worklets": ">=0.13.0" + }, + "peerDependenciesMeta": { + "react-native-worklets": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/@expo/cli": { + "version": "58.1.11", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-58.1.11.tgz", + "integrity": "sha512-wkFTSLXXYqLkRT5oy4DnLuTOtbFIu3qTiXHSHkFSqUBTHiE92y3bOIwM3UN7Y1ys18qVJge8lXjezaEfsHmijQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/code-signing-certificates": "^0.0.7", + "@expo/config": "~58.0.6", + "@expo/config-plugins": "~58.0.9", + "@expo/devcert": "^1.2.2", + "@expo/env": "~2.5.2", + "@expo/image-utils": "^0.12.5", + "@expo/inline-modules": "^0.2.6", + "@expo/json-file": "^11.2.1", + "@expo/log-box": "^58.0.12", + "@expo/log-box-utils": "^58.0.2", + "@expo/metro": "~58.0.0", + "@expo/metro-config": "58.0.14", + "@expo/metro-file-map": "^58.0.5", + "@expo/osascript": "^2.8.1", + "@expo/package-manager": "^1.14.2", + "@expo/platforms": "^58.0.1", + "@expo/plist": "^0.10.1", + "@expo/prebuild-config": "^58.0.14", + "@expo/require-utils": "^58.0.4", + "@expo/router-server": "^58.0.14", + "@expo/schema-utils": "^58.0.2", + "@expo/spawn-async": "^1.8.0", + "@expo/ws-tunnel": "^2.0.1", + "@expo/xcpretty": "^4.4.6", + "@react-native/asset-utils": "0.88.0", + "@react-native/dev-middleware": "0.88.0", + "@react-native/js-polyfills": "0.88.0", + "2g": "^1.0.1", + "accepts": "^1.3.8", + "agent-cli-detector": "0.1.7", + "arg": "^5.0.2", + "bplist-creator": "0.1.0", + "bplist-parser": "^0.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.3.0", + "compression": "^1.7.4", + "connect": "^3.7.0", + "dnssd-advertise": "^1.1.6", + "expo-server": "^58.0.5", + "fetch-nodeshim": "^0.4.10", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "lan-network": "^0.2.1", + "multitars": "^1.0.2", + "node-forge": "^1.4.0", + "npm-package-arg": "^11.0.0", + "ora": "^3.4.0", + "picomatch": "^4.0.4", + "pretty-format": "^29.7.0", + "progress": "^2.0.3", + "prompts": "^2.3.2", + "resolve-from": "^5.0.0", + "sandbox-cli-detector": "^0.2.0", + "semver": "^7.7.4", + "send": "^0.19.0", + "slugify": "^1.3.4", + "stacktrace-parser": "^0.1.10", + "structured-headers": "^0.4.1", + "terminal-link": "^2.1.1", + "toqr": "^0.1.1", + "wrap-ansi": "^7.0.0", + "ws": "^8.12.1", + "zod": "^3.25.76" + }, + "bin": { + "expo-internal": "bin/cli.js" + }, + "peerDependencies": { + "expo": "*", + "expo-router": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "expo-router": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/@expo/cli/node_modules/@expo/router-server": { + "version": "58.0.14", + "resolved": "https://registry.npmjs.org/@expo/router-server/-/router-server-58.0.14.tgz", + "integrity": "sha512-RSzQYMA+Tv2eTemhjhzpx8+hL+pMC30JTVqAWrk5AZwht+OgaKZar/gHmj4iJf7n3rq+GG6KujrkKF9xAXLz2w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "@expo/metro-runtime": "^58.0.14", + "expo": "*", + "expo-constants": "^58.0.12", + "expo-font": "^58.0.8", + "expo-router": "*", + "expo-server": "^58.0.5", + "react": "*", + "react-dom": "*", + "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1 || ~19.3.0" + }, + "peerDependenciesMeta": { + "@expo/metro-runtime": { + "optional": true + }, + "expo-router": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/@expo/config": { + "version": "58.0.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-58.0.6.tgz", + "integrity": "sha512-PT1qv4s/R5A/NxXb4efGlFsYF5Consi7F8xSsJBAN090EGDr6U1EDQGOijFqzDc3JA2epD8zjKLJLOVB9YOewg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/config-plugins": "~58.0.9", + "@expo/config-types": "^58.0.3", + "@expo/json-file": "^11.2.1", + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "deepmerge": "^4.3.1", + "getenv": "^2.0.0", + "glob": "^13.0.0", + "resolve-workspace-root": "^2.0.0", + "semver": "^7.7.4", + "slugify": "^1.3.4" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/@expo/json-file": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@expo/json-file/-/json-file-11.2.1.tgz", + "integrity": "sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "json5": "^2.2.3" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/2g": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/2g/-/2g-1.0.1.tgz", + "integrity": "sha512-+uViadKOS/wwR4pFu5g8TPn3QHpKqoX19JHCnp8k/3cLpImdcXozwvZA6Q/5PeW3AcU8neL8faaMidBcv7o8CA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "2g": "bin/cli.js" + }, + "peerDependencies": { + "typescript": ">=5.8.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/babel-preset-expo": { + "version": "58.0.17", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-58.0.17.tgz", + "integrity": "sha512-Rrqc/Z5Idc4bG2/PrEh725t3kvuAc7jUKCJ+wZVU9KXk2bKSdqAniXxQa8aph9aHdv4h5sGKLpMXMaMNz/4+Og==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/generator": "^7.20.5", + "@babel/helper-module-imports": "^7.25.9", + "@babel/plugin-proposal-decorators": "^7.12.9", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.28.6", + "@babel/plugin-transform-react-jsx-development": "^7.27.1", + "@babel/plugin-transform-react-pure-annotations": "^7.27.1", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/preset-typescript": "^7.23.0", + "@react-native/babel-plugin-codegen": "0.88.0", + "babel-plugin-react-compiler": "^1.0.0", + "babel-plugin-react-native-web": "~0.21.4", + "babel-plugin-syntax-hermes-parser": "^0.36.0", + "babel-plugin-transform-flow-enums": "^0.0.2", + "debug": "^4.3.4" + }, + "peerDependencies": { + "@babel/runtime": "^7.20.0", + "expo": "*", + "expo-widgets": "^58.0.20", + "react-refresh": ">=0.14.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@babel/runtime": { + "optional": true + }, + "expo": { + "optional": true + }, + "expo-widgets": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/expo/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/flow-parser": { + "version": "0.327.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.327.0.tgz", + "integrity": "sha512-/MYZ5hXWf5ozpbdfUDmazMgQXviLxWEiRLH3MppEGDdW0itRVqmB5UaU7QX+SBCDNiq+gEesSVn8nlxmPDyDkw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-estree": "0.327.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/jest-expo": { "version": "54.0.17", "resolved": "https://registry.npmjs.org/jest-expo/-/jest-expo-54.0.17.tgz", @@ -38587,6 +40910,198 @@ } } }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/react-native": { + "version": "0.88.0", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.88.0.tgz", + "integrity": "sha512-v/wee0nYWcammMYBnSat/e3WY/5iaf9YQOMcBrfKT/wPApPPlHp94hgZovBtwhMuthR01yc/8cGn0FpFTE/C4A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@react-native/asset-utils": "0.88.0", + "@react-native/codegen": "0.88.0", + "@react-native/community-cli-plugin": "0.88.0", + "@react-native/gradle-plugin": "0.88.0", + "@react-native/normalize-colors": "0.88.0", + "@react-native/virtualized-lists": "0.88.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "base64-js": "^1.5.1", + "flow-enums-runtime": "^0.0.6", + "flow-parser": "0.327.0", + "hermes-compiler": "260318099.0.4", + "invariant": "^2.2.4", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.87.1", + "metro-source-map": "^0.87.1", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.28.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", + "whatwg-fetch": "^3.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + }, + "peerDependencies": { + "@types/react": "^19.1.1", + "react": "^19.3.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/react-native-worklets": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.13.0.tgz", + "integrity": "sha512-1OrhAeAKaZF4XrBa4YbPQbKzNOpjh52HDlId8e6ete1OCHNdAlrQHzG4gznJ225EAj3dgQXHViJvK51M9B52jQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@babel/generator": "^7.27.1", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.28.6", + "@babel/plugin-transform-classes": "^7.28.6", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.28.6", + "@babel/plugin-transform-optional-chaining": "^7.28.6", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/preset-typescript": "^7.28.5", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "semver": "^7.7.4", + "whatwg-fetch": "^3.6.20" + }, + "peerDependencies": { + "@babel/core": "*", + "@react-native/metro-config": "*", + "react": "*", + "react-native": "0.86 - 0.88" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/react-native/node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/react-native/node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-module-scripts/node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "packages/expo-two-way-audio/node_modules/expo-modules-autolinking": { + "version": "58.0.13", + "resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-58.0.13.tgz", + "integrity": "sha512-uzLFoTnAKabUdITvzRqWTvFkZsOdRPEXj7AEMAuBEhA2kGhqaBDa2EOWqPXVay0QJVoZuIQaEEgPGAXN1dPuYg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@expo/platforms": "^58.0.1", + "@expo/require-utils": "^58.0.4", + "@expo/spawn-async": "^1.8.0", + "chalk": "^4.1.0", + "commander": "^7.2.0" + }, + "bin": { + "expo-modules-autolinking": "bin/expo-modules-autolinking.js" + } + }, + "packages/expo-two-way-audio/node_modules/expo-modules-autolinking/node_modules/@expo/require-utils": { + "version": "58.0.4", + "resolved": "https://registry.npmjs.org/@expo/require-utils/-/require-utils-58.0.4.tgz", + "integrity": "sha512-DvjS5NCitXYcad2Woe1EMHJKcbhTbE77HX0BgOQGL2LFHE3q2H0n8kCWDPBOCVJ63Drap3c35nwoJwF5TQL7Tw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.20.0", + "@babel/core": "^7.25.2", + "@babel/plugin-transform-modules-commonjs": "^7.24.8" + }, + "peerDependencies": { + "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/expo-modules-autolinking/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 10" + } + }, "packages/expo-two-way-audio/node_modules/expo-modules-core": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/expo-modules-core/-/expo-modules-core-2.5.0.tgz", @@ -38597,6 +41112,39 @@ "invariant": "^2.2.4" } }, + "packages/expo-two-way-audio/node_modules/expo-modules-jsi": { + "version": "58.0.15", + "resolved": "https://registry.npmjs.org/expo-modules-jsi/-/expo-modules-jsi-58.0.15.tgz", + "integrity": "sha512-PsjYgL4KWtvBqWH242r0wbP99VjgHkHCpkPCekO7nzb+ulkDNyrNnhysxa0TcNpfRTNLetmCUaLs9t4CcoquZQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "react-native": "*" + } + }, + "packages/expo-two-way-audio/node_modules/expo-server": { + "version": "58.0.5", + "resolved": "https://registry.npmjs.org/expo-server/-/expo-server-58.0.5.tgz", + "integrity": "sha512-FHYecxfGOuAhacHcanR6qCN8Cln9S+FFulcYetLu3ddDg55ohuCsMZ9U4Egzwdm+A2o6N+MdSoJKquBC5F9NIg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": "^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/flow-estree": { + "version": "0.327.0", + "resolved": "https://registry.npmjs.org/flow-estree/-/flow-estree-0.327.0.tgz", + "integrity": "sha512-f9vK751YUzD0qaHSpKc5/qQM6gqOlgGS+4ZRqTNcZOpVqn3mC55yEQ6dUG2K1eaVm5FbKkz9CFWe6XNvrkQFQg==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, "packages/expo-two-way-audio/node_modules/getenv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-2.0.0.tgz", @@ -38638,6 +41186,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/expo-two-way-audio/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/hermes-compiler": { + "version": "260318099.0.4", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-260318099.0.4.tgz", + "integrity": "sha512-8odcPFkPC82HlqCl0C5QI9mBN4rEAT+IAo55sJhzwKw//K3qZloiv3ex6J2O8CuBbhdmkJozfidNsset2KH25w==", + "dev": true, + "license": "MIT", + "peer": true + }, "packages/expo-two-way-audio/node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -38655,6 +41222,21 @@ "hermes-estree": "0.25.1" } }, + "packages/expo-two-way-audio/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "packages/expo-two-way-audio/node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -38707,6 +41289,50 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "packages/expo-two-way-audio/node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, "packages/expo-two-way-audio/node_modules/lru-cache": { "version": "11.5.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", @@ -38717,6 +41343,365 @@ "node": "20 || >=22" } }, + "packages/expo-two-way-audio/node_modules/metro": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.87.1.tgz", + "integrity": "sha512-1oyLU9elM7hPAsKIqKooEekwxiuWr27+MZBhUROPhzcbXhMDxK64GPF/hCXwBZVp1F89ODavCrBmJtLx9WtBoQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "flow-parser": "0.331.0", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.87.1", + "metro-cache": "0.87.1", + "metro-cache-key": "0.87.1", + "metro-config": "0.87.1", + "metro-core": "0.87.1", + "metro-file-map": "0.87.1", + "metro-resolver": "0.87.1", + "metro-runtime": "0.87.1", + "metro-source-map": "0.87.1", + "metro-symbolicate": "0.87.1", + "metro-transform-plugins": "0.87.1", + "metro-transform-worker": "0.87.1", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-babel-transformer": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.87.1.tgz", + "integrity": "sha512-orvRIGpb0yK1yMbk5YP3dhVKjmoxUkRB9fdltGJxNppEqus/1tFpNuf9KnGFR3Qjg0izoUrJ4z6WgoBvdkXPrA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "flow-parser": "0.331.0", + "metro-cache-key": "0.87.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-cache": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.87.1.tgz", + "integrity": "sha512-juNPaj0Xi5tkLp8imXqvbSnEIijwKG36m7OiFFVJMqEkiURwAjkMFVek3/xpix1+LVQqO7kjVp3PvuvIM61mKQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.87.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-cache-key": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.87.1.tgz", + "integrity": "sha512-scqVVPMA2c+RVO12I3wyMDp5xCkRPLsyrcG4Qc3xfU5JR0EW/0sz2tjty+5UjMUtG09uiM1KYQ8HjWg7OQXHtw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-config": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.87.1.tgz", + "integrity": "sha512-NmkDlc/qZAdo5gTkVTuO2AKE/khemRKRH5IA+SKfqUBJigI5GqZ5TOXhmEokhlkAqzjt8dyzKhzI6FHvXoXaTQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.87.1", + "metro-cache": "0.87.1", + "metro-core": "0.87.1", + "metro-runtime": "0.87.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-core": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.87.1.tgz", + "integrity": "sha512-xizzky/4+c/Mkznege8OW05j7bSdM39VPoEps61Se4+hf32UQujmbvLvIE9+UnP6kNEPVomk0Fw8NsBK9iRQmw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.87.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-file-map": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.87.1.tgz", + "integrity": "sha512-9sPuNCojC3pS4vj+ZPY7FXmHGpdJeckXuKXQrDAfJvZc60AF8owRFTkI8XdwlwrmPIB2w++KraK9FMEXvC4wJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-minify-terser": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.87.1.tgz", + "integrity": "sha512-YK4k1oO1wV48hfE+Nbw2rJCnAgeabzrgT/xH5ha5n9gbK4p3HYFC898cERUiyTl9vRh58CNTiXRc88f7y6PfKg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-resolver": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.87.1.tgz", + "integrity": "sha512-FXH/brY69wT6sPxaSW8BhMmDGD/6irmBr/cL4rUi+VWwqR3pbvdcfUOfyjcHucgQ7pe5IW3xJY21eHKLVKNumQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-runtime": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.87.1.tgz", + "integrity": "sha512-kjeuSvInsM6OzBjkCQsWxnkrKZFMKtnkCl38oXWRI9lDGs2L9hGs9Tak9sQYJ9h3gtDujneB7wZio+irgqJKDw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-source-map": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.87.1.tgz", + "integrity": "sha512-Bqpm0PBGdy53pigIJb4HRF7QxD2pUOdgSmVh/4AWbP635kSCv+Y6ltVxUZgSnzS/QbSmzyCGijmRPlXMj2/qHw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.87.1", + "nullthrows": "^1.1.1", + "ob1": "0.87.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-symbolicate": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.87.1.tgz", + "integrity": "sha512-rcGvwabrg0lbXGRGRKl14PY3My3+dkno2jZYhdJEuH2DmjTtTkV5bYwgto4JtV/Lbe+sXE6GO1UGg654430uow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.87.1", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-transform-plugins": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.87.1.tgz", + "integrity": "sha512-qMiJ/x+VfqumFJJSefKS6nj8uojzC29b2/aK8vlMuFABIqGjDucICEOXd2Yt6k/XMFAgAcaJvShUOT0HLyYaPw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro-transform-worker": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.87.1.tgz", + "integrity": "sha512-VOzs3OV405FuOLYdAhqA2wsn1F9lvueDVxMDLvCKaQ44U+yknIqphJ9eMjjsGwLDZiJq9sW3DMLhjD27JxQgqQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.87.1", + "metro-babel-transformer": "0.87.1", + "metro-cache": "0.87.1", + "metro-cache-key": "0.87.1", + "metro-minify-terser": "0.87.1", + "metro-source-map": "0.87.1", + "metro-transform-plugins": "0.87.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/metro/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "packages/expo-two-way-audio/node_modules/metro/node_modules/ws": { + "version": "7.5.13", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.13.tgz", + "integrity": "sha512-rsKI6xDBFVf4r/x8XyChGK04QR/XHroxs/jUcoWvtEZM8TPU/X/uIY9B1CsSzYws9ZJb/6bbBu7dPhFW00CAoA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages/expo-two-way-audio/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "packages/expo-two-way-audio/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=4" + } + }, "packages/expo-two-way-audio/node_modules/minimatch": { "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", @@ -38733,6 +41718,131 @@ "url": "https://github.com/sponsors/isaacs" } }, + "packages/expo-two-way-audio/node_modules/negotiator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "content-type": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "packages/expo-two-way-audio/node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "peer": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "packages/expo-two-way-audio/node_modules/ob1": { + "version": "0.87.1", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.87.1.tgz", + "integrity": "sha512-i8iA8uij0g1YQzS8uOJPSRCgwDjO9warIHUAu1Fqj877Wc3wlfxDYBioYWgKTBF2+URVJttyDWSEpmd99nlvtQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^22.13.0 || ^24.3.0 || >= 26.0.0" + } + }, + "packages/expo-two-way-audio/node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/expo-two-way-audio/node_modules/ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "packages/expo-two-way-audio/node_modules/ora/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/ora/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, "packages/expo-two-way-audio/node_modules/path-scurry": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", @@ -38766,6 +41876,27 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "packages/expo-two-way-audio/node_modules/react": { + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.1.tgz", + "integrity": "sha512-QNhWdt7nrgVWWQG58QuGsAR3jv3Hbe4mb4vz7w2csnHavciZJgda1CPNaldF6eVxv90ud3jUXpKlHL69gO38yw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/expo-two-way-audio/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "packages/expo-two-way-audio/node_modules/react-test-renderer": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-19.1.0.tgz", @@ -38794,6 +41925,29 @@ "node": ">=8" } }, + "packages/expo-two-way-audio/node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC", + "peer": true + }, "packages/expo-two-way-audio/node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -38804,6 +41958,42 @@ "node": ">=8" } }, + "packages/expo-two-way-audio/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/expo-two-way-audio/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "packages/expo-two-way-audio/node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "packages/expo-two-way-audio/node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -38850,6 +42040,28 @@ "node": ">= 6" } }, + "packages/expo-two-way-audio/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "packages/expo-two-way-audio/node_modules/whatwg-url-minimum": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url-minimum/-/whatwg-url-minimum-0.2.0.tgz", + "integrity": "sha512-BtjXU1caNcCFfETP2DhqSeVPfRDl2MTUitI107RE34rJXjR/izfUtR5IoTFOK1WqjNLXbbeqaCH/mQAOLjpc8g==", + "dev": true, + "license": "MIT", + "peer": true + }, "packages/expo-two-way-audio/node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -38860,17 +42072,14 @@ "node": ">=8.0" } }, - "packages/expo-two-way-audio/node_modules/zod-validation-error": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", - "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "packages/expo-two-way-audio/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" + "funding": { + "url": "https://github.com/sponsors/colinhacks" } }, "packages/highlight": { @@ -38914,8 +42123,8 @@ "@getpaseo/protocol": "0.12.0", "@types/node": "^20.9.0", "@types/react": "~19.2.0", - "react": "19.1.0", - "react-native": "0.81.5", + "react": "19.2.3", + "react-native": "0.86.3", "typescript": "^5.9.3", "vitest": "^4.1.6", "zod": "^4.4.3" @@ -38923,7 +42132,7 @@ "peerDependencies": { "@getpaseo/client": "0.12.0", "@getpaseo/protocol": "0.12.0", - "react": "~19.1.0", + "react": ">=19.1.0 <20", "react-native": ">=0.81.5", "zod": "^4.4.3" }, diff --git a/package.json b/package.json index 3cdad0e523..67ca259ffa 100644 --- a/package.json +++ b/package.json @@ -137,16 +137,21 @@ "oxlint-tsgolint": "^0.22.1", "patch-package": "^8.0.1", "playwright": "^1.56.1", + "react-dom": "19.2.3", "typescript": "^5.9.3", "ws": "^8.20.0" }, "overrides": { "@codemirror/language": "6.12.4", "@codemirror/view": "6.43.6", + "expo": "~57.0.30", + "expo-router": "~57.0.28", "lightningcss": "1.30.1", - "react": "19.1.0", - "react-dom": "19.1.0", - "react-native-reanimated": "4.3.1", - "react-native-worklets": "0.8.3" + "react": "19.2.3", + "react-dom": "19.2.3", + "react-native": "0.86.3", + "react-native-gesture-handler": "~2.32.0", + "react-native-reanimated": "4.5.1", + "react-native-worklets": "0.10.1" } } diff --git a/packages/app/app.config.js b/packages/app/app.config.js index e09a06f71d..17bc6fe636 100644 --- a/packages/app/app.config.js +++ b/packages/app/app.config.js @@ -171,6 +171,7 @@ export default { [ "expo-build-properties", { + ios: { enableSceneSupport: true }, android: { minSdkVersion: 29, kotlinVersion: "2.1.20", diff --git a/packages/app/e2e/browser/add-changed-file-to-chat.spec.ts b/packages/app/e2e/browser/add-changed-file-to-chat.spec.ts index c5d4d6cb15..af3ea5454f 100644 --- a/packages/app/e2e/browser/add-changed-file-to-chat.spec.ts +++ b/packages/app/e2e/browser/add-changed-file-to-chat.spec.ts @@ -2,48 +2,56 @@ import { mkdir, writeFile } from "node:fs/promises"; import path from "node:path"; import { test, expect, type Page } from "../support/fixtures"; import { seedMockAgentWorkspace, openAgentRoute } from "../support/helpers/mock-agent"; -import { openChangesPanel } from "../support/helpers/workspace-tabs"; +import { openChangesPanel, openChangesTreePanel } from "../support/helpers/workspace-tabs"; function visibleComposer(page: Page) { return page.locator("textarea[data-composer-input]").filter({ visible: true }).first(); } -test("adds a changed file to the focused chat without replacing its composer draft", async ({ - page, -}) => { - const workspace = await seedMockAgentWorkspace({ - repoPrefix: "add-file-to-chat-", - title: "Target chat", - }); - const relativePath = "src/changed file.ts"; - - try { - await mkdir(path.join(workspace.cwd, "src"), { recursive: true }); - await writeFile(path.join(workspace.cwd, relativePath), "export const changed = true;\n"); - await workspace.client.checkoutRefresh(workspace.cwd); - - await page.setViewportSize({ width: 1400, height: 900 }); - await openAgentRoute(page, { - workspaceId: workspace.workspaceId, - agentId: workspace.agentId, +for (const width of [1400, 390]) { + test(`adds a changed file to the focused chat without replacing its composer draft at ${width}px`, async ({ + page, + }) => { + const workspace = await seedMockAgentWorkspace({ + repoPrefix: "add-file-to-chat-", + title: "Target chat", }); + const relativePath = "src/changed file.ts"; - const agentComposer = visibleComposer(page); - await expect(agentComposer).toBeEditable({ timeout: 30_000 }); - await agentComposer.fill("Preserve this thought"); + try { + await mkdir(path.join(workspace.cwd, "src"), { recursive: true }); + await writeFile(path.join(workspace.cwd, relativePath), "export const changed = true;\n"); + await workspace.client.checkoutRefresh(workspace.cwd); - await openChangesPanel(page); - const changedFile = page.getByText("changed file.ts", { exact: true }).first(); - await expect(changedFile).toBeVisible({ timeout: 30_000 }); - await page.getByTestId("diff-file-0-toggle").click({ button: "right" }); - await page.getByTestId("diff-file-0-add-to-chat").click(); + await page.setViewportSize({ width, height: 900 }); + await openAgentRoute(page, { + workspaceId: workspace.workspaceId, + agentId: workspace.agentId, + }); - const attachment = page.getByTestId("composer-workspace-file-attachment-pill"); - await expect(attachment).toContainText("changed file.ts"); - await expect(attachment).toContainText(relativePath); - await expect(agentComposer).toHaveValue("Preserve this thought"); - await expect(agentComposer).toBeFocused(); - } finally { - await workspace.cleanup(); - } -}); + const agentComposer = visibleComposer(page); + await expect(agentComposer).toBeEditable({ timeout: 30_000 }); + await agentComposer.fill("Preserve this thought"); + + if (width < 600) await openChangesTreePanel(page); + else await openChangesPanel(page); + const changedFile = page.getByTestId("diff-file-0-toggle"); + await expect(changedFile).toBeVisible({ timeout: 30_000 }); + await page.getByTestId("diff-file-0-toggle").click({ button: "right" }); + await page.getByTestId("diff-file-0-add-to-chat").click(); + + const attachment = page.getByTestId("composer-workspace-file-attachment-pill"); + if (width < 600) + await expect( + page.getByTestId("workspace-explorer-sidebar").filter({ visible: true }), + ).toHaveCount(0); + await expect(attachment).toContainText("changed file.ts"); + await expect(attachment).toContainText(relativePath); + await expect(agentComposer).toHaveValue("Preserve this thought"); + if (width >= 600) await expect(agentComposer).toBeFocused(); + else await expect(agentComposer).toBeEditable(); + } finally { + await workspace.cleanup(); + } + }); +} diff --git a/packages/app/e2e/browser/changes-pane.spec.ts b/packages/app/e2e/browser/changes-pane.spec.ts index 377adbb3b6..2218e1bf3b 100644 --- a/packages/app/e2e/browser/changes-pane.spec.ts +++ b/packages/app/e2e/browser/changes-pane.spec.ts @@ -833,13 +833,15 @@ test("compact Changes keeps its actions compact and menu-only", async ({ page }) await openWorkspaceChanges(page, workspace); await page.setViewportSize({ width: 480, height: 900 }); - const compactChangesTab = page.getByTestId("explorer-tab-changes").filter({ visible: true }); + const compactChangesTab = page + .getByTestId("workspace-tab-changes_tree") + .filter({ visible: true }); if (!(await compactChangesTab.isVisible())) { await page.getByTestId("workspace-explorer-toggle").first().click(); } await expect(compactChangesTab).toBeVisible(); await compactChangesTab.click(); - const compactExplorer = page.getByTestId("explorer-content-area").filter({ visible: true }); + const compactExplorer = page.getByTestId("workspace-explorer-sidebar").filter({ visible: true }); await expect(compactExplorer.getByTestId("changes-header")).toBeVisible(); const actions = compactExplorer.getByTestId("changes-actions-menu-trigger"); @@ -876,6 +878,27 @@ test("compact Changes keeps its actions compact and menu-only", async ({ page }) ).toContainText("Scroll long lines"); }); +test("compact Explorer renders inline hunks with a saved tree-only desktop preference", async ({ + page, +}) => { + const workspace = await createWorkspaceWithMountedTabDiff(); + await page.addInitScript( + ({ key }) => { + localStorage.setItem(key, JSON.stringify({ inlineDiff: false, layout: "split" })); + }, + { key: CHANGES_PREFERENCES_KEY }, + ); + const explorer = await openCompactChanges(page, workspace); + await expect(explorer.getByTestId("git-diff-canvas")).toBeVisible(); + await expect(explorer.getByTestId("diff-file-0-toggle")).toBeVisible(); + await explorer.getByTestId("diff-file-0-toggle").click({ button: "right" }); + page.once("dialog", (dialog) => dialog.accept()); + await page.getByTestId("diff-file-0-revert").click(); + await expect + .poll(() => readFile(path.join(workspace.repoPath, "src/use-mounted-tab-set.ts"), "utf8")) + .toBe(BEFORE); +}); + test("compact Changes jumps to a file from the changed-files sheet", async ({ page }) => { const workspace = await createWorkspaceWithMountedTabDiff({ includeNestedFolders: true }); await useUnwrappedDiffLines(page); @@ -1674,10 +1697,10 @@ async function openCompactChanges(page: Page, workspace: DirtyWorkspace): Promis await page.goto(buildHostWorkspaceRoute(getServerId(), workspace.id)); await page.reload(); await page.getByTestId("workspace-explorer-toggle").first().click(); - const changesTab = page.getByTestId("explorer-tab-changes").filter({ visible: true }); + const changesTab = page.getByTestId("workspace-tab-changes_tree").filter({ visible: true }); await expect(changesTab).toBeVisible({ timeout: 30_000 }); await changesTab.click(); - const explorer = page.getByTestId("explorer-content-area").filter({ visible: true }); + const explorer = page.getByTestId("workspace-explorer-sidebar").filter({ visible: true }); await expect(explorer.getByTestId("changes-header")).toBeVisible({ timeout: 30_000 }); return explorer; } diff --git a/packages/app/e2e/browser/compact-git-actions-menu.spec.ts b/packages/app/e2e/browser/compact-git-actions-menu.spec.ts index 8198ecea5f..e2e2cdb34f 100644 --- a/packages/app/e2e/browser/compact-git-actions-menu.spec.ts +++ b/packages/app/e2e/browser/compact-git-actions-menu.spec.ts @@ -45,10 +45,10 @@ async function openCompactActionsMenu(page: Page, workspaceId: string) { await page.goto(buildHostWorkspaceRoute(getServerId(), workspaceId)); await page.reload(); await page.getByTestId("workspace-explorer-toggle").first().click(); - const changesTab = page.getByTestId("explorer-tab-changes").filter({ visible: true }); + const changesTab = page.getByTestId("workspace-tab-changes_tree").filter({ visible: true }); await expect(changesTab).toBeVisible({ timeout: 30_000 }); await changesTab.click(); - const explorer = page.getByTestId("explorer-content-area").filter({ visible: true }); + const explorer = page.getByTestId("workspace-explorer-sidebar").filter({ visible: true }); await expect(explorer.getByTestId("changes-header")).toBeVisible({ timeout: 30_000 }); const trigger = explorer.getByTestId("changes-actions-menu-trigger"); diff --git a/packages/app/e2e/browser/composer-diff-stat.spec.ts b/packages/app/e2e/browser/composer-diff-stat.spec.ts index b3d1b56c12..9b80222432 100644 --- a/packages/app/e2e/browser/composer-diff-stat.spec.ts +++ b/packages/app/e2e/browser/composer-diff-stat.spec.ts @@ -125,7 +125,7 @@ test("composer diff stat opens the compact explorer instead of a Changes tab", a }); const closeExplorer = page - .getByTestId("explorer-header") + .getByTestId("workspace-explorer-sidebar") .getByRole("button", { name: "Close Explorer sidebar" }); await expect(closeExplorer).not.toBeInViewport(); @@ -809,7 +809,7 @@ async function expectUnmatchedFeedback(page: Page) { } function compactReviewSurface(page: Page) { - return page.getByTestId("explorer-content-area").filter({ visible: true }); + return page.getByTestId("workspace-explorer-sidebar").filter({ visible: true }); } async function openCompactReviewExplorer( page: Page, @@ -847,7 +847,10 @@ async function scrollReviewToLastLine(page: Page) { async function revealCompactChanges(page: Page) { await page.getByTestId("workspace-explorer-toggle").first().click(); - await page.getByTestId("explorer-header").getByText("Changes", { exact: true }).click(); + await page + .getByTestId("workspace-explorer-sidebar") + .getByTestId("workspace-tab-changes_tree") + .click(); await expect(compactReviewSurface(page).getByTestId("diff-file-0-body")).toBeVisible(); } async function expectReviewEditorBody(page: Page, body: string) { diff --git a/packages/app/e2e/browser/explorer-sidebar.spec.ts b/packages/app/e2e/browser/explorer-sidebar.spec.ts index c8536c884a..06a6994332 100644 --- a/packages/app/e2e/browser/explorer-sidebar.spec.ts +++ b/packages/app/e2e/browser/explorer-sidebar.spec.ts @@ -1,3 +1,7 @@ +import { seedMockAgentWorkspace, openAgentRoute } from "../support/helpers/mock-agent"; +import { writeFile } from "node:fs/promises"; +import { openFileFromExplorer } from "../support/helpers/file-explorer"; +import { openSettingsSection, clickSettingsBackToWorkspace } from "../support/helpers/settings"; import { expect, test } from "../support/fixtures"; import { gotoWorkspace, @@ -136,10 +140,9 @@ test("Explorer keeps Files and Changes close actions in the context menu", async await explorer.getByRole("button", { name: "New tab", exact: true }).click(); const menu = page.getByTestId("workspace-new-tab-menu").filter({ visible: true }); await expect(menu).toBeVisible(); - await expect(menu.getByRole("menuitem", { name: /^Agent/ })).toHaveCount(0); + await expect(menu.getByRole("menuitem", { name: /^Agent/ })).toHaveCount(1); await expect(menu.getByRole("menuitem", { name: /^Files/ })).toHaveCount(0); await expect(menu.getByRole("menuitem", { name: /^Changes/ })).toHaveCount(0); - await expect(menu.getByText("Terminal profiles", { exact: true })).toHaveCount(0); await expect(menu.getByRole("menuitem", { name: /^Terminal/ })).toBeVisible(); const entries = await menu.getByRole("menuitem").allTextContents(); expect(entries.findIndex((entry) => entry.startsWith("Terminal"))).toBeLessThan( @@ -191,13 +194,11 @@ test("Explorer keeps Files and Changes close actions in the context menu", async } }); -async function dragAgentIntoExplorer( +async function dragTabIntoExplorer( page: Parameters[0], - agentId: string, + tabId: string, ) { - const source = page - .getByTestId("workspace-pane-main") - .getByTestId(`workspace-tab-agent_${agentId}`); + const source = page.getByTestId("workspace-pane-main").getByTestId(`workspace-tab-${tabId}`); const destination = explorerSidebar(page).getByTestId("workspace-tab-files"); const sourceBox = await source.boundingBox(); const destinationBox = await destination.boundingBox(); @@ -213,7 +214,7 @@ async function dragAgentIntoExplorer( await page.mouse.up(); } -test("agents can still be dragged into Explorer when absent from its + menu", async ({ +test("moves agents into Explorer and keeps the shared Agent launcher available", async ({ page, }, testInfo) => { const workspace = await seedWorkspace({ repoPrefix: "explorer-agent-drag-" }); @@ -230,14 +231,13 @@ test("agents can still be dragged into Explorer when absent from its + menu", as }); const main = page.getByTestId("workspace-pane-main"); await expect(main.getByTestId(`workspace-tab-agent_${agent.id}`)).toBeVisible(); - await dragAgentIntoExplorer(page, agent.id); + await dragTabIntoExplorer(page, `agent_${agent.id}`); await expect(explorer.getByTestId(`workspace-tab-agent_${agent.id}`)).toBeVisible(); await expect(main.getByTestId(`workspace-tab-agent_${agent.id}`)).toHaveCount(0); await explorer.getByRole("button", { name: "New tab", exact: true }).click(); const menu = page.getByTestId("workspace-new-tab-menu").filter({ visible: true }); await expect(menu).toBeVisible(); - await expect(menu.getByRole("menuitem", { name: /^Agent/ })).toHaveCount(0); - await expect(menu.getByText("Terminal profiles", { exact: true })).toHaveCount(0); + await expect(menu.getByRole("menuitem", { name: /^Agent/ })).toHaveCount(1); await page.keyboard.press("Escape"); await testInfo.attach("agent-in-explorer", { body: await page.screenshot(), @@ -247,3 +247,273 @@ test("agents can still be dragged into Explorer when absent from its + menu", as await workspace.cleanup(); } }); + +test("tablet prototype keeps Explorer tabs when resizing down to a phone", async ({ + page, +}, testInfo) => { + const workspace = await seedWorkspace({ repoPrefix: "tablet-explorer-" }); + try { + await page.setViewportSize({ width: 951, height: 669 }); + await gotoWorkspace(page, workspace.workspaceId); + await waitForWorkspaceTabsVisible(page); + await ensureExplorerSidebar(page); + await expect( + explorerSidebar(page).getByRole("button", { name: "Browse workspace files", exact: true }), + ).toBeVisible(); + await page.screenshot({ path: testInfo.outputPath("tablet-951.png") }); + await openExplorerAgentDraft(page); + await page.screenshot({ path: testInfo.outputPath("tablet-agent-draft.png") }); + await page.setViewportSize({ width: 390, height: 844 }); + await revealPhoneExplorer(page); + await expect( + explorerSidebar(page).getByRole("button", { name: "New tab", exact: true }), + ).toBeVisible(); + await page.screenshot({ path: testInfo.outputPath("phone-shared-explorer.png") }); + } finally { + await workspace.cleanup(); + } +}); + +async function openExplorerAgentDraft(page: Parameters[0]) { + await explorerSidebar(page).getByRole("button", { name: "New tab", exact: true }).click(); + await page.getByRole("menuitem", { name: /^Agent/ }).click(); + await expect(explorerSidebar(page).getByRole("textbox").first()).toBeVisible(); +} + +async function revealPhoneExplorer(page: Parameters[0]) { + await page.getByRole("button", { name: "Open Explorer sidebar", exact: true }).click(); + await expect(explorerSidebar(page)).toBeVisible(); + await expect( + explorerSidebar(page).getByRole("button", { name: "Close Explorer sidebar", exact: true }), + ).toBeInViewport({ ratio: 1 }); +} + +async function cycleWorkspaceTheme(page: Parameters[0]) { + await page.keyboard.press("Control+Alt+t"); +} + +test("retains the Explorer host through appearance changes and folding", async ({ page }) => { + const workspace = await seedWorkspace({ repoPrefix: "explorer-lifetime-" }); + try { + await gotoWorkspace(page, workspace.workspaceId); + const explorer = await ensureExplorerSidebar(page); + await openFilesPanel(page); + const host = await explorer.elementHandle(); + if (!host) throw new Error("Explorer must be mounted before changing appearance"); + const previousColor = await explorer.evaluate( + (element) => getComputedStyle(element).backgroundColor, + ); + await cycleWorkspaceTheme(page); + await expect + .poll(() => explorer.evaluate((element) => getComputedStyle(element).backgroundColor)) + .not.toBe(previousColor); + expect(await host.evaluate((element) => element.isConnected)).toBe(true); + await page.setViewportSize({ width: 390, height: 844 }); + await ensureExplorerSidebar(page); + expect(await host.evaluate((element) => element.isConnected)).toBe(true); + await page.setViewportSize({ width: 1280, height: 900 }); + await expect(explorer).toBeVisible(); + expect(await host.evaluate((element) => element.isConnected)).toBe(true); + } finally { + await workspace.cleanup(); + } +}); + +async function reorderCompactExplorerTabs(page: Parameters[0]) { + const explorer = explorerSidebar(page); + const files = explorer.getByTestId("workspace-tab-files"); + const changes = explorer.getByTestId("workspace-tab-changes_tree"); + const source = await changes.boundingBox(); + const target = await files.boundingBox(); + if (!source || !target) throw new Error("Explorer tabs must be visible to reorder"); + await page.mouse.move(source.x + source.width / 2, source.y + source.height / 2); + await page.mouse.down(); + await page.mouse.move(source.x + source.width / 2 - 12, source.y + source.height / 2); + await page.mouse.move(target.x + 3, target.y + target.height / 2, { steps: 20 }); + await page.mouse.up(); + await expect + .poll(async () => { + const afterFiles = await files.boundingBox(); + const afterChanges = await changes.boundingBox(); + return Boolean(afterFiles && afterChanges && afterChanges.x < afterFiles.x); + }) + .toBe(true); +} + +test("reorders compact Explorer tabs with a pointer without changing selection", async ({ + page, +}) => { + const workspace = await seedWorkspace({ repoPrefix: "explorer-compact-drag-" }); + try { + await gotoWorkspace(page, workspace.workspaceId); + await page.setViewportSize({ width: 390, height: 844 }); + await openFilesPanel(page); + await reorderCompactExplorerTabs(page); + await expect( + explorerSidebar(page).getByRole("button", { name: "Browse workspace files", exact: true }), + ).toHaveAttribute("aria-selected", "true"); + } finally { + await workspace.cleanup(); + } +}); + +// Exercise appearance at its consumers while the real workspace navigator retains the panels. +test("updates populated code and diff appearance without losing the editor instance or draft", async ({ + page, +}) => { + const workspace = await seedWorkspace({ repoPrefix: "explorer-populated-appearance-" }); + const source = Array.from( + { length: 120 }, + (_, index) => `export const line${index} = "retained ${index}";`, + ).join("\n"); + try { + await writeFile(`${workspace.repoPath}/appearance.ts`, source); + await page.addInitScript(() => { + localStorage.setItem( + "@paseo:app-settings", + JSON.stringify({ codeFontSize: 13, theme: "light" }), + ); + localStorage.setItem( + "@paseo:changes-preferences", + JSON.stringify({ inlineDiff: true, layout: "unified" }), + ); + }); + await gotoWorkspace(page, workspace.workspaceId); + await openFilesPanel(page); + await openFileFromExplorer(page, "appearance.ts"); + const editor = page.getByTestId("file-source-editor").filter({ visible: true }); + const text = editor.locator(".cm-content"); + await expect(text).toBeVisible(); + await text.fill(`${source}\n// unsaved local edit`); + const instance = await editor.elementHandle(); + const scroller = editor.locator(".cm-scroller"); + await scroller.evaluate((node) => { + node.scrollTop = 400; + }); + const scrollBefore = await scroller.evaluate((node) => node.scrollTop); + await explorerSidebar(page).getByTestId("workspace-tab-changes_tree").click(); + const diff = explorerSidebar(page).getByTestId("git-diff-canvas"); + await expect(diff).toBeVisible(); + await page.keyboard.press("Control+,"); + await openSettingsSection(page, "appearance"); + await page.getByLabel("Code font size", { exact: true }).fill("19"); + await page.getByLabel("Code font size", { exact: true }).press("Tab"); + await clickSettingsBackToWorkspace(page); + await expect(text).toHaveCSS("font-size", "19px"); + expect(await instance!.evaluate((node) => node.isConnected)).toBe(true); + await expect(text).toContainText("unsaved local edit"); + expect(await scroller.evaluate((node) => node.scrollTop)).toBe(scrollBefore); + await expect(diff).toHaveCSS("font-size", "19px"); + await cycleWorkspaceTheme(page); + expect(await instance!.evaluate((node) => node.isConnected)).toBe(true); + await expect(text).toContainText("unsaved local edit"); + await dragTabIntoExplorer(page, "file_appearance.ts"); + await expect(explorerSidebar(page).getByTestId("file-source-editor")).toBeVisible(); + const explorerEditor = await explorerSidebar(page) + .getByTestId("file-source-editor") + .elementHandle(); + await text.fill(`${source}\n// retained Explorer edit`); + await page.setViewportSize({ width: 390, height: 844 }); + await ensureExplorerSidebar(page); + await page.setViewportSize({ width: 1280, height: 900 }); + expect(await explorerEditor!.evaluate((node) => node.isConnected)).toBe(true); + await expect(text).toContainText("retained Explorer edit"); + } finally { + await workspace.cleanup(); + } +}); + +test("retains populated Explorer chat and terminal attachments through appearance, hide and fold", async ({ + page, +}) => { + const workspace = await seedMockAgentWorkspace({ + repoPrefix: "explorer-chat-appearance-", + title: "Retained chat", + initialPrompt: "Show the retention marker", + featureValues: { + mockAssistantResponse: "Explorer populated paragraph.\n\n```ts\nconst retained = 42;\n```", + }, + }); + const attaches: string[] = []; + page.on("websocket", (socket) => + socket.on("framesent", (frame) => { + if (typeof frame.payload !== "string") return; + try { + const message = JSON.parse(frame.payload).message; + if (message?.type === "subscribe_terminal_request") attaches.push(message.terminalId); + } catch { + /* Binary terminal traffic is not a JSON request. */ + } + }), + ); + try { + await openAgentRoute(page, workspace); + await ensureExplorerSidebar(page); + await dragTabIntoExplorer(page, `agent_${workspace.agentId}`); + const explorer = explorerSidebar(page); + const paragraph = explorer.getByText("Explorer populated paragraph.", { exact: true }); + await expect(paragraph).toBeVisible(); + const composer = explorer.getByRole("textbox", { name: "Message agent..." }); + await composer.fill("Unsubmitted Explorer draft"); + const composerNode = await composer.elementHandle(); + await page.keyboard.press("Control+,"); + await openSettingsSection(page, "appearance"); + await page.getByLabel("Content font size", { exact: true }).fill("20"); + await page.getByLabel("Content font size", { exact: true }).press("Tab"); + await clickSettingsBackToWorkspace(page); + await expect(paragraph).toHaveCSS("font-size", "20px"); + expect(await composerNode!.evaluate((node) => node.isConnected)).toBe(true); + await expect(composer).toHaveValue("Unsubmitted Explorer draft"); + const previousColor = await paragraph.evaluate((node) => getComputedStyle(node).color); + await cycleWorkspaceTheme(page); + await expect + .poll(() => paragraph.evaluate((node) => getComputedStyle(node).color)) + .not.toBe(previousColor); + await explorer.getByRole("button", { name: "New tab", exact: true }).click(); + await page + .getByRole("menuitem", { name: /^Terminal/ }) + .first() + .click(); + const terminal = explorer.getByTestId("terminal-surface"); + await expect(terminal).toBeVisible(); + await expect.poll(() => attaches.length).toBe(1); + const terminalNode = await terminal.elementHandle(); + await page.getByTestId("workspace-explorer-toggle").first().click(); + await ensureExplorerSidebar(page); + await page.setViewportSize({ width: 390, height: 844 }); + await ensureExplorerSidebar(page); + await page.setViewportSize({ width: 1280, height: 900 }); + await cycleWorkspaceTheme(page); + expect(await terminalNode!.evaluate((node) => node.isConnected)).toBe(true); + expect(attaches).toHaveLength(1); + await explorer.getByTestId(`workspace-tab-agent_${workspace.agentId}`).click(); + expect(await composerNode!.evaluate((node) => node.isConnected)).toBe(true); + await expect(composer).toHaveValue("Unsubmitted Explorer draft"); + await expect(paragraph).toHaveCSS("font-size", "20px"); + } finally { + await workspace.cleanup(); + } +}); + +test("compact file sheets cover Explorer and return to its retained file list", async ({ + page, +}) => { + const workspace = await seedWorkspace({ repoPrefix: "explorer-sheet-layer-" }); + try { + await writeFile(`${workspace.repoPath}/sheet-marker.txt`, "Explorer sheet marker\n"); + await gotoWorkspace(page, workspace.workspaceId); + await page.setViewportSize({ width: 390, height: 844 }); + const explorer = await ensureExplorerSidebar(page); + await openFilesPanel(page); + const host = await explorer.elementHandle(); + await openFileFromExplorer(page, "sheet-marker.txt"); + await expect(page.getByText("Explorer sheet marker", { exact: true })).toBeVisible(); + // A real click also proves the sheet draws above the retained Explorer overlay. + await page.getByRole("button", { name: "Close", exact: true }).click(); + await expect(page.getByText("Explorer sheet marker", { exact: true })).toHaveCount(0); + await expect(explorer.getByTestId("file-explorer-tree-scroll")).toBeVisible(); + expect(await host!.evaluate((node) => node.isConnected)).toBe(true); + } finally { + await workspace.cleanup(); + } +}); diff --git a/packages/app/e2e/browser/new-workspace-launch-terminal.spec.ts b/packages/app/e2e/browser/new-workspace-launch-terminal.spec.ts index d393966ee8..7268f7146b 100644 --- a/packages/app/e2e/browser/new-workspace-launch-terminal.spec.ts +++ b/packages/app/e2e/browser/new-workspace-launch-terminal.spec.ts @@ -247,9 +247,7 @@ test.describe("New workspace: fullscreen composer across the compact breakpoint" await expectNewWorkspaceDraft(page, `${draft} wide`); }); - // Terminal mode and its prompt are screen state, and the shell remounts the screen - // at the breakpoint, so the terminal prompt's fullscreen is exercised on the phone - // layout only. + // Exercise the terminal prompt's fullscreen and compact launch sheet on the phone. await test.step("terminal: the prompt's fullscreen shows only exit and Launch", async () => { await resizeComposerViewport(page, "portrait"); // The compact launch control opens a sheet, not the desktop menu. diff --git a/packages/app/e2e/browser/plugin-host-ui.spec.ts b/packages/app/e2e/browser/plugin-host-ui.spec.ts index 84d786033a..1d952fe92f 100644 --- a/packages/app/e2e/browser/plugin-host-ui.spec.ts +++ b/packages/app/e2e/browser/plugin-host-ui.spec.ts @@ -5,10 +5,6 @@ import path from "node:path"; import { expect, test, type Page } from "../support/fixtures"; import { gotoAppShell } from "../support/helpers/app"; import { connectNewWorkspaceDaemonClient } from "../support/helpers/new-workspace"; -import { - expectMobileAgentSidebarVisible, - openMobileAgentSidebar, -} from "../support/helpers/sidebar"; const PLUGIN_ID = "plugin-host-ui-e2e"; @@ -91,12 +87,6 @@ async function useCompactLayout(page: Page): Promise { await page.setViewportSize({ width: 390, height: 844 }); } -async function reopenHostUiPluginFromCompactSidebar(page: Page): Promise { - await openMobileAgentSidebar(page); - await expectMobileAgentSidebarVisible(page); - await page.getByRole("button", { name: "Host UI", exact: true }).click(); -} - async function openPluginModal(page: Page): Promise { await page.getByRole("button", { name: "Open plugin modal", exact: true }).click(); } @@ -158,7 +148,6 @@ test("plugin modal adapts its presentation and preserves host contexts", async ( await test.step("compact layouts preserve host contexts inside a sheet", async () => { await useCompactLayout(page); - await reopenHostUiPluginFromCompactSidebar(page); await openPluginModal(page); await expectCompactPluginSheet(page); await savePluginIssue(page); diff --git a/packages/app/e2e/browser/plugin-modal-body.spec.ts b/packages/app/e2e/browser/plugin-modal-body.spec.ts index bdd822b9c8..33be8a5c40 100644 --- a/packages/app/e2e/browser/plugin-modal-body.spec.ts +++ b/packages/app/e2e/browser/plugin-modal-body.spec.ts @@ -2,10 +2,6 @@ import { copyPluginExample } from "../support/helpers/plugin-fixture"; import { expect, test as base, type Page } from "../support/fixtures"; import { gotoAppShell } from "../support/helpers/app"; import { connectNewWorkspaceDaemonClient } from "../support/helpers/new-workspace"; -import { - openMobileAgentSidebar, - expectMobileAgentSidebarVisible, -} from "../support/helpers/sidebar"; async function openExample(page: Page, example: string) { await page.getByRole("button", { name: `Open ${example}`, exact: true }).click(); @@ -122,9 +118,7 @@ async function openWideExamples(page: Page) { async function openCompactExamples(page: Page) { await page.setViewportSize({ width: 390, height: 844 }); - await openMobileAgentSidebar(page); - await expectMobileAgentSidebarVisible(page); - await page.getByRole("button", { name: "Modal examples", exact: true }).click(); + await expect(page.getByRole("button", { name: "Open Form", exact: true })).toBeVisible(); } async function expectDeniedCopyFeedback(page: Page) { diff --git a/packages/app/e2e/browser/sidebar-mobile-menu-sheets.spec.ts b/packages/app/e2e/browser/sidebar-mobile-menu-sheets.spec.ts index 7b4c36bf97..8b06e14f67 100644 --- a/packages/app/e2e/browser/sidebar-mobile-menu-sheets.spec.ts +++ b/packages/app/e2e/browser/sidebar-mobile-menu-sheets.spec.ts @@ -15,6 +15,7 @@ async function closeMenuSheet(page: Page): Promise { test("project and workspace kebabs open action sheets on compact layouts", async ({ page }) => { const seeded = await seedWorkspace({ repoPrefix: "sidebar-mobile-menu-sheet-" }); + const secondProject = await seedWorkspace({ repoPrefix: "sidebar-mobile-menu-filter-" }); try { await gotoAppShell(page); @@ -26,6 +27,7 @@ test("project and workspace kebabs open action sheets on compact layouts", async /^Grouping/, /^Title/, "Show", + "Project", "Show background", ]); await closeMenuSheet(page); @@ -53,6 +55,7 @@ test("project and workspace kebabs open action sheets on compact layouts", async }); await expect(page.getByText("Workspace actions", { exact: true })).toBeVisible(); } finally { + await secondProject.cleanup(); await seeded.cleanup(); } }); diff --git a/packages/app/e2e/browser/sidebar-workspace.spec.ts b/packages/app/e2e/browser/sidebar-workspace.spec.ts index 85de01a376..d96f68580c 100644 --- a/packages/app/e2e/browser/sidebar-workspace.spec.ts +++ b/packages/app/e2e/browser/sidebar-workspace.spec.ts @@ -624,7 +624,9 @@ test.describe("Half-screen desktop layout", () => { await expect(page.getByTestId("sidebar-settings")).not.toBeVisible(); }); - test("keeps app navigation beside the Explorer pane", async ({ page }) => { + test("yields app navigation to Explorer and restores it when Explorer closes", async ({ + page, + }) => { const workspace = await seedWorkspace({ repoPrefix: "sidebar-half-screen-explorer-" }); try { @@ -636,7 +638,7 @@ test.describe("Half-screen desktop layout", () => { const explorerToggle = page.getByTestId("workspace-explorer-toggle").first(); await expect(page.getByTestId("workspace-tab-files").filter({ visible: true })).toBeVisible(); await expect(explorerToggle).toHaveAccessibleName("Close Explorer sidebar"); - await expect(page.getByTestId("sidebar-global-new-workspace")).toBeVisible(); + await expect(page.getByTestId("sidebar-global-new-workspace")).not.toBeVisible(); await expect(page.getByTestId("workspace-explorer-sidebar")).toBeVisible(); await expect( page diff --git a/packages/app/e2e/browser/usage-modal.spec.ts b/packages/app/e2e/browser/usage-modal.spec.ts index b680754da2..1d98f6c591 100644 --- a/packages/app/e2e/browser/usage-modal.spec.ts +++ b/packages/app/e2e/browser/usage-modal.spec.ts @@ -608,7 +608,10 @@ for (const compact of [false, true]) { if (compact) await openCompactSidebar(page); await openUsageFromIcon(page); await expectLoginErrors(page, ["Claude: Initial failure"]); - await expectLoginUsageFreshness(page, "No successful update", compact); + await test.step("developer errors do not interrupt freshness inspection", async () => { + await page.evaluate(() => console.error("E2E: developer toast while Usage is open")); + await expectLoginUsageFreshness(page, "No successful update", compact); + }); await fixture.setReport({ status: "available", diff --git a/packages/app/e2e/mobile/agent-device/file-context-menu.ios.ad b/packages/app/e2e/mobile/agent-device/file-context-menu.ios.ad index 9f758a2806..279009d380 100644 --- a/packages/app/e2e/mobile/agent-device/file-context-menu.ios.ad +++ b/packages/app/e2e/mobile/agent-device/file-context-menu.ios.ad @@ -4,8 +4,8 @@ env APP_ID=sh.paseo.debug open "${APP_ID}" wait "id=\"workspace-header-menu-trigger\"" 20000 press "id=\"workspace-explorer-toggle\"" -wait "id=\"explorer-tab-files\"" 10000 -press "id=\"explorer-tab-files\"" +wait "id=\"workspace-tab-files\"" 10000 +press "id=\"workspace-tab-files\"" wait "id=\"file-explorer-row-0\"" 10000 longpress "id=\"file-explorer-row-0\"" 600 wait "id=\"file-explorer-row-0-context-menu-content\"" 10000 diff --git a/packages/app/e2e/support/developer-ui.mjs b/packages/app/e2e/support/developer-ui.mjs new file mode 100644 index 0000000000..36d5752688 --- /dev/null +++ b/packages/app/e2e/support/developer-ui.mjs @@ -0,0 +1,10 @@ +/** @param {import('@playwright/test').Page} page */ +export async function installDeveloperToastDismissal(page) { + // Developer chrome must not cover app actions or move the test's pointer/focus. + // Console errors remain in the runner's logs. + const dismiss = page.locator("#error-toast").getByRole("button", { name: "", exact: true }); + await page.addLocatorHandler(dismiss, () => dismiss.dispatchEvent("click"), { + // A new logged error can replace the toast before the old one disappears. + noWaitAfter: true, + }); +} diff --git a/packages/app/e2e/support/fixtures.ts b/packages/app/e2e/support/fixtures.ts index 43b4191b64..aa83df8e91 100644 --- a/packages/app/e2e/support/fixtures.ts +++ b/packages/app/e2e/support/fixtures.ts @@ -1,4 +1,5 @@ import { test as base, expect, type Page } from "@playwright/test"; +import { installDeveloperToastDismissal } from "./developer-ui.mjs"; import { startOutdatedDaemon, type OutdatedDaemon } from "./helpers/daemon-update"; import { startE2EWorker } from "./helpers/e2e-worker"; import { getE2EDaemonPort } from "./helpers/daemon-port"; @@ -130,6 +131,8 @@ const test = daemonTest.extend<{ await ws.close({ code: 1008, reason: "Blocked connection to localhost:6767 during e2e." }); }); + await installDeveloperToastDismissal(page); + const entries: string[] = []; page.on("console", (message) => { diff --git a/packages/app/e2e/support/global-setup.ts b/packages/app/e2e/support/global-setup.ts index 29257af299..00041de6a7 100644 --- a/packages/app/e2e/support/global-setup.ts +++ b/packages/app/e2e/support/global-setup.ts @@ -134,6 +134,8 @@ function startMetro(port: number, buffer: ReturnType): env: { ...process.env, BROWSER: "none", + // Automation never opens native DevTools or installs its desktop shell. + EXPO_UNSTABLE_HEADLESS: "1", ...(process.env.E2E_DESKTOP_RUNTIME === "1" ? { PASEO_WEB_PLATFORM: "electron" } : {}), }, stdio: ["ignore", "pipe", "pipe"], diff --git a/packages/app/e2e/support/helpers/composer.ts b/packages/app/e2e/support/helpers/composer.ts index 971b1ad1b9..19183fee4b 100644 --- a/packages/app/e2e/support/helpers/composer.ts +++ b/packages/app/e2e/support/helpers/composer.ts @@ -363,10 +363,11 @@ export async function resizeComposerViewport( await page.setViewportSize(sizes[orientation]); // Before the app has loaded there is no layout to wait for. if (page.url() === "about:blank") return; - // Crossing the compact breakpoint remounts the shell and the editor. Anything that - // follows (a shortcut, a locator) belongs to the layout the new size implies, so - // wait for that layout before returning. - await expect(page.getByTestId("compact-shell")).toHaveCount(orientation === "landscape" ? 0 : 1); + // The shell and editor survive the breakpoint. Wait for the shell's layout + // marker to update before interacting with the resized composer. + await expect( + page.getByTestId(orientation === "landscape" ? "wide-shell" : "compact-shell"), + ).toBeVisible(); } export async function selectComposerDraftRange( page: Page, diff --git a/packages/app/e2e/support/helpers/context-window.ts b/packages/app/e2e/support/helpers/context-window.ts index 21341c7766..afc91f859c 100644 --- a/packages/app/e2e/support/helpers/context-window.ts +++ b/packages/app/e2e/support/helpers/context-window.ts @@ -37,7 +37,7 @@ export async function hoverContextWindowMeter(page: Page, name = METER_NAME): Pr await page.getByRole("img", { name, exact: true }).hover({ timeout: 30_000 }); const card = contextWindowDetails(page); await expect(card).toBeVisible(); - await expect(card).toBeInViewport(); + await expect(card).toBeInViewport({ ratio: 1 }); return card; } diff --git a/packages/app/e2e/support/helpers/sidebar.ts b/packages/app/e2e/support/helpers/sidebar.ts index 500ce8bd41..5b7b819bf0 100644 --- a/packages/app/e2e/support/helpers/sidebar.ts +++ b/packages/app/e2e/support/helpers/sidebar.ts @@ -276,15 +276,22 @@ export async function swipeOpenMobileExplorer(page: Page): Promise { } export async function closeMobileExplorer(page: Page): Promise { - const closeButton = page.getByTestId("explorer-close"); + const closeButton = page + .getByTestId("workspace-explorer-sidebar") + .getByRole("button", { name: "Close Explorer sidebar", exact: true }); await expect(closeButton).toBeInViewport({ ratio: 1, timeout: 5_000 }); await closeButton.click(); } export async function expectMobileExplorerVisible(page: Page): Promise { - await expect(page.getByTestId("explorer-header")).toBeInViewport({ ratio: 1, timeout: 5_000 }); + await expect(page.getByTestId("workspace-explorer-sidebar")).toBeInViewport({ + ratio: 1, + timeout: 5_000, + }); } export async function expectMobileExplorerHidden(page: Page): Promise { - await expect(page.getByTestId("explorer-header")).not.toBeInViewport({ timeout: 5_000 }); + await expect(page.getByTestId("workspace-explorer-sidebar")).not.toBeInViewport({ + timeout: 5_000, + }); } diff --git a/packages/app/package.json b/packages/app/package.json index 0584846dd0..7f1ff46029 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -58,11 +58,11 @@ "@marijn/find-cluster-break": "^1.0.2", "@mattermost/react-native-paste-input": "2.0.1", "@react-native-async-storage/async-storage": "2.2.0", - "@react-native-masked-view/masked-view": "^0.3.2", - "@react-native/normalize-colors": "^0.81.5", + "@react-native-masked-view/masked-view": "0.3.2", + "@react-native/normalize-colors": "0.86.3", "@react-navigation/native": "^7.1.8", "@replit/codemirror-vim": "6.3.0", - "@shopify/react-native-skia": "2.2.12", + "@shopify/react-native-skia": "2.6.2", "@tanstack/react-query": "^5.90.11", "@tanstack/react-virtual": "^3.13.21", "@xterm/addon-clipboard": "^0.3.0-beta.213", @@ -75,30 +75,30 @@ "@xterm/addon-webgl": "^0.20.0-beta.212", "@xterm/xterm": "^6.1.0-beta.213", "buffer": "^6.0.3", - "expo": "^54.0.18", - "expo-asset": "~12.0.12", - "expo-audio": "~1.0.13", - "expo-build-properties": "^1.0.9", - "expo-camera": "~17.0.10", - "expo-clipboard": "~8.0.7", - "expo-constants": "~18.0.9", - "expo-crypto": "^15.0.8", - "expo-dev-client": "^6.0.15", - "expo-document-picker": "~14.0.8", - "expo-file-system": "~19.0.17", - "expo-haptics": "~15.0.7", - "expo-image": "~3.0.10", - "expo-image-manipulator": "~14.0.8", - "expo-image-picker": "^17.0.8", - "expo-keep-awake": "^15.0.7", - "expo-linking": "~8.0.8", - "expo-localization": "~17.0.9", - "expo-notifications": "^0.32.16", - "expo-router": "~6.0.13", - "expo-sharing": "^14.0.8", - "expo-splash-screen": "~31.0.10", - "expo-sqlite": "~16.0.10", - "expo-system-ui": "~6.0.7", + "expo": "~57.0.30", + "expo-asset": "~57.0.20", + "expo-audio": "~57.0.5", + "expo-build-properties": "~57.0.22", + "expo-camera": "~57.0.6", + "expo-clipboard": "~57.0.2", + "expo-constants": "~57.0.22", + "expo-crypto": "~57.0.4", + "expo-dev-client": "~57.0.20", + "expo-document-picker": "~57.0.3", + "expo-file-system": "~57.0.7", + "expo-haptics": "~57.0.3", + "expo-image": "~57.0.5", + "expo-image-manipulator": "~57.0.21", + "expo-image-picker": "~57.0.20", + "expo-keep-awake": "~57.0.2", + "expo-linking": "~57.0.13", + "expo-localization": "~57.0.2", + "expo-notifications": "~57.0.23", + "expo-router": "~57.0.28", + "expo-sharing": "~57.0.23", + "expo-splash-screen": "~57.0.10", + "expo-sqlite": "~57.0.4", + "expo-system-ui": "~57.0.4", "fast-deep-equal": "^3.1.3", "htmlparser2": "^12.0.0", "i18next": "^26.3.0", @@ -111,25 +111,25 @@ "micromark-util-decode-string": "2.0.1", "mnemonic-id": "^3.2.7", "qrcode": "^1.5.4", - "react": "19.1.0", - "react-dom": "19.1.0", + "react": "19.2.3", + "react-dom": "19.2.3", "react-freeze": "1.0.4", "react-i18next": "^17.0.8", - "react-native": "0.81.5", + "react-native": "0.86.3", "react-native-draggable-flatlist": "^4.0.3", "react-native-edge-to-edge": "^1.7.0", "react-native-enriched-markdown": "1.2.0-nightly-20261014-766fc0e67", - "react-native-gesture-handler": "~2.28.0", + "react-native-gesture-handler": "~2.32.0", "react-native-keyboard-controller": "1.21.12", "react-native-nitro-modules": "0.35.5", - "react-native-reanimated": "~4.3.1", - "react-native-safe-area-context": "~5.6.0", - "react-native-screens": "~4.16.0", - "react-native-svg": "^15.14.0", + "react-native-reanimated": "4.5.1", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "~4.26.0", + "react-native-svg": "15.15.4", "react-native-unistyles": "^3.2.4", "react-native-web": "~0.21.0", - "react-native-webview": "^13.16.0", - "react-native-worklets": "~0.8.3", + "react-native-webview": "13.16.1", + "react-native-worklets": "0.10.1", "tiny-invariant": "^1.3.3", "turndown": "^7.2.4", "turndown-plugin-gfm": "^1.0.2", @@ -151,11 +151,12 @@ "@vitest/browser": "^4.1.7", "@vitest/browser-playwright": "^4.1.7", "@xterm/headless": "^6.1.0-beta.213", + "babel-preset-expo": "~57.0.16", "dotenv": "^17.2.3", "eas-cli": "^16.24.1", "esbuild": "0.28.1", "eslint": "^9.25.0", - "eslint-config-expo": "~10.0.0", + "eslint-config-expo": "~57.0.2", "expo-gradle-jvmargs": "^1.1.2", "fake-indexeddb": "^6.2.5", "jsdom": "^20.0.3", diff --git a/packages/app/plugins/with-paste-input.js b/packages/app/plugins/with-paste-input.js index 76be6a8fcd..cc5660646e 100644 --- a/packages/app/plugins/with-paste-input.js +++ b/packages/app/plugins/with-paste-input.js @@ -4,26 +4,33 @@ const { IOSConfig, withAppDelegate, withDangerousMod, + withInfoPlist, withPodfile, } = require("expo/config-plugins"); -const MODULE_SETUP = " PasteInputModule.setup(factory.rootViewFactory)"; -const REACT_NATIVE_START_END = " launchOptions: launchOptions)\n#endif"; const BRIDGING_HEADER_IMPORT = "#import "; -const PODFILE_NEW_ARCH_DISABLED = - "ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false'"; -const PODFILE_NEW_ARCH_ENABLED = - "ENV['RCT_NEW_ARCH_ENABLED'] ||= '1' if podfile_properties['newArchEnabled'] == 'true'"; +const SCENE_DELEGATE = ` +@objc(PaseoSceneDelegate) +class PaseoSceneDelegate: ExpoAppSceneDelegate { + override func scene( + _ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions + ) { + super.scene(scene, willConnectTo: session, options: connectionOptions) + guard let provider = UIApplication.shared.delegate as? ExpoReactNativeFactoryProvider, + let factory = provider.reactNativeFactory else { return } + PasteInputModule.setup(factory.rootViewFactory) + } +} +`; function configurePasteInputAppDelegate(contents) { - const configured = contents.replace(`\n${MODULE_SETUP}`, ""); - if (!configured.includes(REACT_NATIVE_START_END)) { - throw new Error("Could not register paste input after React Native starts"); + if (contents.includes("class PaseoSceneDelegate:")) return contents; + if (!contents.includes("ExpoReactNativeFactoryProvider")) { + throw new Error("Paste input requires Expo scene support"); } - return configured.replace( - REACT_NATIVE_START_END, - ` launchOptions: launchOptions)\n${MODULE_SETUP}\n#endif`, - ); + return `${contents.trimEnd()}\n${SCENE_DELEGATE}`; } function configurePasteInputBridgingHeader(contents) { @@ -33,19 +40,6 @@ function configurePasteInputBridgingHeader(contents) { return `${contents.trimEnd()}\n${BRIDGING_HEADER_IMPORT}\n`; } -function configurePasteInputPodfile(contents) { - if (contents.includes(PODFILE_NEW_ARCH_ENABLED)) { - return contents; - } - if (!contents.includes(PODFILE_NEW_ARCH_DISABLED)) { - throw new Error("Could not configure the new architecture for paste input"); - } - return contents.replace( - PODFILE_NEW_ARCH_DISABLED, - `${PODFILE_NEW_ARCH_DISABLED}\n${PODFILE_NEW_ARCH_ENABLED}`, - ); -} - function withPasteInput(config) { const withDelegate = withAppDelegate(config, (modConfig) => { if (modConfig.modResults.language !== "swift") { @@ -54,7 +48,18 @@ function withPasteInput(config) { modConfig.modResults.contents = configurePasteInputAppDelegate(modConfig.modResults.contents); return modConfig; }); - const withPods = withPodfile(withDelegate, (modConfig) => { + const withScene = withInfoPlist(withDelegate, (modConfig) => { + const scenes = + modConfig.modResults.UIApplicationSceneManifest?.UISceneConfigurations + ?.UIWindowSceneSessionRoleApplication; + if (!scenes || scenes.length !== 1) { + throw new Error("Paste input requires Expo's single scene configuration"); + } + scenes[0].UISceneDelegateClassName = "PaseoSceneDelegate"; + return modConfig; + }); + const withPods = withPodfile(withScene, (modConfig) => { + // Paste input checks this legacy flag even though RN 0.86 only supports Fabric. modConfig.modResults.contents = configurePasteInputPodfile(modConfig.modResults.contents); return modConfig; }); @@ -79,4 +84,9 @@ function withPasteInputBridgingHeader(config) { module.exports = withPasteInput; module.exports.configurePasteInputAppDelegate = configurePasteInputAppDelegate; module.exports.configurePasteInputBridgingHeader = configurePasteInputBridgingHeader; + +function configurePasteInputPodfile(contents) { + const flag = "ENV['RCT_NEW_ARCH_ENABLED'] = '1'"; + return contents.includes(flag) ? contents : `${flag}\n${contents}`; +} module.exports.configurePasteInputPodfile = configurePasteInputPodfile; diff --git a/packages/app/plugins/with-paste-input.test.ts b/packages/app/plugins/with-paste-input.test.ts index fdc271d7ab..4412570ddb 100644 --- a/packages/app/plugins/with-paste-input.test.ts +++ b/packages/app/plugins/with-paste-input.test.ts @@ -7,22 +7,14 @@ const { } = require("./with-paste-input"); describe("withPasteInput", () => { - it("registers the module after React Native starts", () => { - const source = [ - "import ReactAppDependencyProvider", - "", - " bindReactNativeFactory(factory)", - " factory.startReactNative(", - ' withModuleName: "main",', - " in: window,", - " launchOptions: launchOptions)", - "#endif", - ].join("\n"); + it("registers paste input after Expo connects the React Native scene", () => { + const source = "class AppDelegate: ExpoAppDelegate, ExpoReactNativeFactoryProvider {}"; const configured = configurePasteInputAppDelegate(source); - - expect(configured).toContain( - " launchOptions: launchOptions)\n PasteInputModule.setup(factory.rootViewFactory)\n#endif", + expect(configured).toContain("class PaseoSceneDelegate: ExpoAppSceneDelegate"); + expect(configured.indexOf("super.scene(")).toBeLessThan( + configured.indexOf("PasteInputModule.setup("), ); + expect(configured).toContain("provider.reactNativeFactory"); expect(configurePasteInputAppDelegate(configured)).toBe(configured); }); @@ -33,15 +25,11 @@ describe("withPasteInput", () => { expect(configured).toContain("#import "); expect(configurePasteInputBridgingHeader(configured)).toBe(configured); }); - - it("sets the new architecture environment before CocoaPods evaluates dependencies", () => { + it("enables the legacy new-architecture flag required by the paste input podspec", () => { const source = - "ENV['RCT_NEW_ARCH_ENABLED'] ||= '0' if podfile_properties['newArchEnabled'] == 'false'"; + "require File.join(File.dirname(`node --print \"require.resolve('expo/package.json')\"`), 'scripts/autolinking')"; const configured = configurePasteInputPodfile(source); - - expect(configured).toContain( - "ENV['RCT_NEW_ARCH_ENABLED'] ||= '1' if podfile_properties['newArchEnabled'] == 'true'", - ); + expect(configured).toBe("ENV['RCT_NEW_ARCH_ENABLED'] = '1'\n" + source); expect(configurePasteInputPodfile(configured)).toBe(configured); }); }); diff --git a/packages/app/src/agent-skills/index.tsx b/packages/app/src/agent-skills/index.tsx index 04fdbd2294..1241192b50 100644 --- a/packages/app/src/agent-skills/index.tsx +++ b/packages/app/src/agent-skills/index.tsx @@ -1,7 +1,7 @@ import { useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Text, View } from "react-native"; -import { useFocusEffect } from "@react-navigation/native"; +import { useFocusEffect } from "expo-router/react-navigation"; import { StyleSheet, withUnistyles } from "react-native-unistyles"; import { ArrowUpRight, Blocks, Check, Settings2 } from "lucide-react-native"; import type { AgentSkillOperation, AgentSkillsStatus } from "@getpaseo/protocol/messages"; diff --git a/packages/app/src/agent-stream/view.tsx b/packages/app/src/agent-stream/view.tsx index da2fd59d36..d662a2f345 100644 --- a/packages/app/src/agent-stream/view.tsx +++ b/packages/app/src/agent-stream/view.tsx @@ -445,11 +445,6 @@ const AgentStreamViewComponent = forwardRef state.desktop.focusModeEnabled); const isDesktopAgentListOpen = usePanelStore((state) => state.desktop.agentListOpen); const sidebarWidth = usePanelStore((state) => state.sidebarWidth); - const { width: viewportWidth } = useWindowDimensions(); + const { width: windowWidth } = useWindowDimensions(); + const insets = useSafeAreaInsets(); + const viewportWidth = windowWidth - insets.left - insets.right; const cycleTheme = useCallback(() => { void updateSettings({ theme: getNextThemePreference(settings.theme) }); }, [settings.theme, updateSettings]); const isCompactLayout = useIsCompactFormFactor(); - const explorerSidebarPresentation = resolveExplorerSidebarPresentation({ - isCompact: isCompactLayout, - }); - const usesCompactExplorerHost = explorerSidebarPresentation !== "pane"; useCompactWebViewportZoomLock(isCompactLayout); const pathname = usePathname(); const isWorkspaceRoute = parseHostWorkspaceRouteFromPathname(pathname) !== null; @@ -516,7 +516,15 @@ function AppContainer({ children, chromeEnabled: chromeEnabledOverride }: AppCon useActiveWorktreeNewAction(); useGlobalNewWorkspaceAction(); + const activeWorkspace = useActiveWorkspaceSelection(); + const explorerVisible = useIsExplorerSidebarOpen({ + isCompact: isCompactLayout, + workspaceKey: activeWorkspace + ? `${activeWorkspace.serverId}:${activeWorkspace.workspaceId}` + : null, + }); const appContentMinimumWidth = resolveDesktopAppContentMinimum({ + explorerVisible: isWorkspaceRoute && explorerVisible, isSettingsRoute: pathname.includes("/settings"), }); const desktopSidebarMounted = hasMountedDesktopSidebar && !isWorkspaceFocusModeEnabled; @@ -548,28 +556,25 @@ function AppContainer({ children, chromeEnabled: chromeEnabledOverride }: AppCon if (isWeb) { themedSidebarChrome = {sidebarChrome}; } + const workspaceChromeStyle = useMemo( + () => [rowStyle, !isCompactLayout && { paddingLeft: insets.left, paddingRight: insets.right }], + [insets.left, insets.right, isCompactLayout], + ); const workspaceChrome = ( - + {!isCompactLayout ? ( {themedSidebarChrome} ) : null} - {usesCompactExplorerHost ? ( - + - - {children} - - - ) : ( - {children} - )} + ); @@ -620,15 +625,27 @@ function AppContainer({ children, chromeEnabled: chromeEnabledOverride }: AppCon ); - const content = isCompactLayout ? ( - {surface} - ) : ( - surface + return ( + + {surface} + ); +} +function AppContainerLifetime({ + children, + compactGesturesEnabled, +}: { + children: ReactNode; + compactGesturesEnabled: boolean; +}) { return ( - {content} + + + {children} + + ); } @@ -662,10 +679,15 @@ function MobileGestureWrapper({ chromeEnabled: boolean; }) { const openGesture = useOpenAgentListGesture(chromeEnabled); + const isCompactLayout = useIsCompactFormFactor(); return ( - + {children} diff --git a/packages/app/src/app/h/[serverId]/_layout.tsx b/packages/app/src/app/h/[serverId]/_layout.tsx index 1a47093e2c..df16818239 100644 --- a/packages/app/src/app/h/[serverId]/_layout.tsx +++ b/packages/app/src/app/h/[serverId]/_layout.tsx @@ -10,6 +10,8 @@ const HOST_STACK_SCREEN_OPTIONS = { animation: "none" as const, }; +const SCREEN_OWNED_APPEARANCE = ["workspace/[workspaceId]/index"] as const; + const AGENT_SCREEN_OPTIONS = { gestureEnabled: false }; export default function HostRouteLayout() { @@ -34,7 +36,10 @@ function KnownHostRoute() { } const stack = ( - + diff --git a/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/index.tsx b/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/index.tsx index 7dc11b08f1..80ba6df4d4 100644 --- a/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/index.tsx +++ b/packages/app/src/app/h/[serverId]/workspace/[workspaceId]/index.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; -import { useNavigation } from "@react-navigation/native"; +import { useNavigation } from "expo-router/react-navigation"; import { StyleSheet, View } from "react-native"; import { useGlobalSearchParams, useLocalSearchParams, useRootNavigationState } from "expo-router"; import { HostRouteBootstrapBoundary } from "@/components/host-route-bootstrap-boundary"; diff --git a/packages/app/src/app/pair-scan.tsx b/packages/app/src/app/pair-scan.tsx index 6aea5225d6..5d352140ee 100644 --- a/packages/app/src/app/pair-scan.tsx +++ b/packages/app/src/app/pair-scan.tsx @@ -33,7 +33,7 @@ const styles = StyleSheet.create((theme) => ({ flex: 1, }, overlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, justifyContent: "center", alignItems: "center", }, diff --git a/packages/app/src/command-center/command-center.tsx b/packages/app/src/command-center/command-center.tsx index febac60a14..58f1a4ce54 100644 --- a/packages/app/src/command-center/command-center.tsx +++ b/packages/app/src/command-center/command-center.tsx @@ -943,7 +943,7 @@ const styles = StyleSheet.create((theme) => ({ alignItems: "center", paddingTop: theme.spacing[12], }, - backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: "rgba(0, 0, 0, 0.5)" }, + backdrop: { ...StyleSheet.absoluteFill, backgroundColor: "rgba(0, 0, 0, 0.5)" }, panel: { width: 640, height: 560, diff --git a/packages/app/src/components/adaptive-modal-sheet.tsx b/packages/app/src/components/adaptive-modal-sheet.tsx index d4d833e3f1..f487f07f07 100644 --- a/packages/app/src/components/adaptive-modal-sheet.tsx +++ b/packages/app/src/components/adaptive-modal-sheet.tsx @@ -66,7 +66,7 @@ export interface SheetHeader { } const SCROLL_CONTENT_GROW = { flexGrow: 1 }; -const ABSOLUTE_FILL_STYLE = { ...StyleSheet.absoluteFillObject }; +const ABSOLUTE_FILL_STYLE = { ...StyleSheet.absoluteFill }; const NATIVE_DIALOG_SNAP_POINTS = ["100%"]; const styles = StyleSheet.create((theme) => ({ @@ -77,7 +77,7 @@ const styles = StyleSheet.create((theme) => ({ backgroundColor: "transparent", }, desktopOverlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, backgroundColor: "rgba(0,0,0,0.55)", justifyContent: "center", alignItems: "center", diff --git a/packages/app/src/components/add-project-flow.tsx b/packages/app/src/components/add-project-flow.tsx index c331f237c5..06f7872995 100644 --- a/packages/app/src/components/add-project-flow.tsx +++ b/packages/app/src/components/add-project-flow.tsx @@ -1007,7 +1007,7 @@ const styles = StyleSheet.create((theme) => ({ paddingTop: theme.spacing[12], }, backdrop: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, backgroundColor: "rgba(0, 0, 0, 0.5)", }, panel: { diff --git a/packages/app/src/components/appearance-style-boundary.test.ts b/packages/app/src/components/appearance-style-boundary.test.ts index da6fb85c45..5e73ce36f9 100644 --- a/packages/app/src/components/appearance-style-boundary.test.ts +++ b/packages/app/src/components/appearance-style-boundary.test.ts @@ -20,54 +20,53 @@ describe("appearanceStyleBoundaryKey", () => { // This is a placement contract against the production JSX, not a simulated native mount. // Native Gesture Handler/Fabric lifetime behavior is verified on the release app. describe("retained native gesture host appearance placement", () => { - it.each([ - ["../app/_layout.tsx", ["sidebarChrome", "themedSidebarChrome"]], - [ - "./compact-explorer-sidebar-host.tsx", - ["explorer", "themedExplorer", "CompactExplorerSidebar", "NativeExplorerSidebarDock"], - ], - ] as const)("keeps native hosts outside appearance keys in %s", (path, hosts) => { - const source = ts.createSourceFile( - path, - readFileSync(new URL(path, import.meta.url), "utf8"), - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TSX, - ); - let hostsFound = 0; - let webKeysFound = 0; - function visit(node: ts.Node) { - let name: string | undefined; - if (ts.isIdentifier(node)) name = node.text; - if (ts.isJsxSelfClosingElement(node)) name = node.tagName.getText(source); - if (name && hosts.some((host) => host === name)) { - hostsFound++; - let webOnly = false; - let keyed = false; - for ( - let child = node, parent = node.parent; - parent; - child = parent, parent = parent.parent - ) { - if ( - ts.isIfStatement(parent) && - parent.expression.getText(source) === "isWeb" && - parent.thenStatement === child - ) - webOnly = true; - if ( - ts.isJsxElement(parent) && - parent.openingElement.tagName.getText(source) === "AppearanceStyleBoundary" - ) - keyed = true; + it.each([["../app/_layout.tsx", ["sidebarChrome", "themedSidebarChrome"], true]] as const)( + "keeps native hosts outside appearance keys in %s", + (path, hosts, hasWebKeys) => { + const source = ts.createSourceFile( + path, + readFileSync(new URL(path, import.meta.url), "utf8"), + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.TSX, + ); + let hostsFound = 0; + let webKeysFound = 0; + function visit(node: ts.Node) { + let name: string | undefined; + if (ts.isIdentifier(node)) name = node.text; + if (ts.isJsxSelfClosingElement(node)) name = node.tagName.getText(source); + if (name && hosts.some((host) => host === name)) { + hostsFound++; + let webOnly = false; + let keyed = false; + for ( + let child = node, parent = node.parent; + parent; + child = parent, parent = parent.parent + ) { + if ( + ts.isIfStatement(parent) && + parent.expression.getText(source) === "isWeb" && + parent.thenStatement === child + ) + webOnly = true; + if ( + ts.isJsxElement(parent) && + parent.openingElement.tagName.getText(source) === "AppearanceStyleBoundary" + ) + keyed = true; + } + if (keyed && webOnly) webKeysFound++; + expect(keyed && !webOnly, `${name} is remounted on native appearance changes`).toBe( + false, + ); } - if (keyed && webOnly) webKeysFound++; - expect(keyed && !webOnly, `${name} is remounted on native appearance changes`).toBe(false); + ts.forEachChild(node, visit); } - ts.forEachChild(node, visit); - } - visit(source); - expect(hostsFound).toBeGreaterThan(0); - expect(webKeysFound).toBeGreaterThan(0); - }); + visit(source); + expect(hostsFound).toBeGreaterThan(0); + if (hasWebKeys) expect(webKeysFound).toBeGreaterThan(0); + }, + ); }); diff --git a/packages/app/src/components/compact-explorer-sidebar-host-state.test.ts b/packages/app/src/components/compact-explorer-sidebar-host-state.test.ts deleted file mode 100644 index 0e55872c0a..0000000000 --- a/packages/app/src/components/compact-explorer-sidebar-host-state.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - resolveCompactExplorerSidebarHostModel, - type CompactExplorerSidebarHostModel, -} from "@/components/compact-explorer-sidebar-host-state"; -import type { WorkspaceDescriptor } from "@/stores/session-store"; - -function createWorkspace( - input: Partial & Pick, -): WorkspaceDescriptor { - return { - id: input.id, - projectId: input.projectId ?? "project-1", - projectDisplayName: input.projectDisplayName ?? "Project 1", - projectRootPath: input.projectRootPath ?? "/repo", - workspaceDirectory: input.workspaceDirectory ?? "/repo", - projectKind: input.projectKind ?? "git", - workspaceKind: input.workspaceKind ?? "local_checkout", - name: input.name ?? "main", - status: input.status ?? "done", - archivingAt: input.archivingAt ?? null, - statusEnteredAt: null, - diffStat: input.diffStat ?? null, - scripts: input.scripts ?? [], - }; -} - -function createModel( - overrides: Partial = {}, -): CompactExplorerSidebarHostModel { - return { - serverId: overrides.serverId ?? "server-1", - workspaceId: overrides.workspaceId ?? "workspace-a", - persistenceKey: overrides.persistenceKey ?? "server-1:workspace-a", - workspaceRoot: overrides.workspaceRoot ?? "/repo/a", - isGit: overrides.isGit ?? true, - }; -} - -describe("resolveCompactExplorerSidebarHostModel", () => { - it("retains the last workspace root for the same active selection while the workspace reloads", () => { - const previous = createModel(); - - const result = resolveCompactExplorerSidebarHostModel({ - previous, - selection: { serverId: "server-1", workspaceId: "workspace-a" }, - workspace: null, - isGit: false, - }); - - expect(result).toEqual({ - serverId: "server-1", - workspaceId: "workspace-a", - persistenceKey: "server-1:workspace-a", - workspaceRoot: "/repo/a", - isGit: true, - }); - }); - - it("switches ownership to the active workspace instead of leaking the previous one", () => { - const previous = createModel(); - - const result = resolveCompactExplorerSidebarHostModel({ - previous, - selection: { serverId: "server-1", workspaceId: "workspace-b" }, - workspace: null, - isGit: false, - }); - - expect(result).toEqual({ - serverId: "server-1", - workspaceId: "workspace-b", - persistenceKey: "server-1:workspace-b", - workspaceRoot: "", - isGit: false, - }); - }); - - it("does not retain a previous owner when there is no active workspace selection", () => { - const result = resolveCompactExplorerSidebarHostModel({ - previous: createModel(), - selection: null, - workspace: null, - isGit: false, - }); - - expect(result).toBeNull(); - }); - - it("uses the current workspace directory when it is available", () => { - const result = resolveCompactExplorerSidebarHostModel({ - previous: null, - selection: { serverId: "server-1", workspaceId: "workspace-a" }, - workspace: createWorkspace({ id: "workspace-a", workspaceDirectory: "/repo/current" }), - isGit: true, - }); - - expect(result).toEqual({ - serverId: "server-1", - workspaceId: "workspace-a", - persistenceKey: "server-1:workspace-a", - workspaceRoot: "/repo/current", - isGit: true, - }); - }); -}); diff --git a/packages/app/src/components/compact-explorer-sidebar-host-state.ts b/packages/app/src/components/compact-explorer-sidebar-host-state.ts deleted file mode 100644 index 8d44a9d767..0000000000 --- a/packages/app/src/components/compact-explorer-sidebar-host-state.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { buildWorkspaceTabPersistenceKey } from "@/workspace-tabs/model"; -import type { ActiveWorkspaceSelection } from "@/stores/navigation-active-workspace-store"; -import type { WorkspaceDescriptor } from "@/stores/session-store"; - -export interface CompactExplorerSidebarHostModel { - serverId: string; - workspaceId: string; - persistenceKey: string; - workspaceRoot: string; - isGit: boolean; -} - -interface ResolveCompactExplorerSidebarHostModelInput { - previous: CompactExplorerSidebarHostModel | null; - selection: ActiveWorkspaceSelection | null; - workspace: WorkspaceDescriptor | null; - isGit: boolean; -} - -function trimNonEmpty(value: string | null | undefined): string | null { - if (typeof value !== "string") { - return null; - } - const trimmed = value.trim(); - return trimmed.length > 0 ? trimmed : null; -} - -export function resolveCompactExplorerSidebarHostModel( - input: ResolveCompactExplorerSidebarHostModelInput, -): CompactExplorerSidebarHostModel | null { - const serverId = trimNonEmpty(input.selection?.serverId); - const workspaceId = trimNonEmpty(input.selection?.workspaceId); - if (!serverId || !workspaceId) { - return null; - } - - const persistenceKey = buildWorkspaceTabPersistenceKey({ serverId, workspaceId }); - if (!persistenceKey) { - return null; - } - - const previousForSelection = - input.previous && - input.previous.serverId === serverId && - input.previous.workspaceId === workspaceId - ? input.previous - : null; - - return { - serverId, - workspaceId, - persistenceKey, - workspaceRoot: - trimNonEmpty(input.workspace?.workspaceDirectory) ?? - previousForSelection?.workspaceRoot ?? - "", - isGit: input.workspace ? input.isGit : (previousForSelection?.isGit ?? input.isGit), - }; -} diff --git a/packages/app/src/components/compact-explorer-sidebar-host.tsx b/packages/app/src/components/compact-explorer-sidebar-host.tsx deleted file mode 100644 index 2dae4b9042..0000000000 --- a/packages/app/src/components/compact-explorer-sidebar-host.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { View, type LayoutChangeEvent } from "react-native"; -import { GestureDetector } from "react-native-gesture-handler"; -import { useActiveWorkspaceSelection } from "@/stores/navigation-active-workspace-store"; -import { useWorkspace } from "@/stores/session-store-hooks"; -import { - CompactExplorerSidebar, - NativeExplorerSidebarDock, -} from "@/components/compact-explorer-sidebar"; -import { useOpenFileExplorerGesture } from "@/mobile-panels/gestures"; -import { useIsMobilePanelActive } from "@/mobile-panels/provider"; -import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; -import { usePanelStore } from "@/stores/panel-store"; -import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; -import type { WorkspaceTabTarget } from "@/workspace-tabs/model"; -import { useWorkspaceCheckoutStatus } from "@/screens/workspace/use-workspace-checkout-status"; -import { openWorkspaceFileFromExplorer } from "@/screens/workspace/workspace-file-open-command"; -import { isWeb } from "@/constants/platform"; -import { DiffDocumentWorkspaceCacheProvider } from "@/git/diff-document/workspace-cache"; -import { - resolveCompactExplorerSidebarHostModel, - type CompactExplorerSidebarHostModel, -} from "@/components/compact-explorer-sidebar-host-state"; -import { AppearanceStyleBoundary } from "@/components/appearance-style-boundary"; - -interface CompactExplorerOpenGestureSurfaceProps { - children: ReactNode; - enabled: boolean; - onOpenExplorer: () => void; -} - -const COMPACT_WEB_GESTURE_TOUCH_ACTION = isWeb ? "auto" : "pan-y"; - -function CompactExplorerOpenGestureSurface({ - children, - enabled, - onOpenExplorer, -}: CompactExplorerOpenGestureSurfaceProps) { - const explorerOpenGesture = useOpenFileExplorerGesture({ - enabled, - onOpen: onOpenExplorer, - }); - - return ( - - {children} - - ); -} - -function useActiveCompactExplorerSidebarModel( - enabled: boolean, -): CompactExplorerSidebarHostModel | null { - const selection = useActiveWorkspaceSelection(); - const workspace = useWorkspace(selection?.serverId ?? null, selection?.workspaceId ?? null); - const isExplorerActive = useIsMobilePanelActive("file-explorer"); - const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const client = useHostRuntimeClient(selection?.serverId ?? ""); - const isConnected = useHostRuntimeIsConnected(selection?.serverId ?? ""); - const retainedModelRef = useRef(null); - const { checkoutQuery } = useWorkspaceCheckoutStatus({ - client, - isConnected, - isRouteFocused: enabled && selection !== null, - normalizedServerId: selection?.serverId ?? "", - normalizedWorkspaceId: selection?.workspaceId ?? "", - workspaceDirectory: workspace?.workspaceDirectory || null, - }); - const resolvedModel = useMemo( - () => - resolveCompactExplorerSidebarHostModel({ - previous: isExplorerActive ? retainedModelRef.current : null, - selection, - workspace, - isGit: checkoutQuery.data?.isGit ?? false, - }), - [checkoutQuery.data?.isGit, isExplorerActive, selection, workspace], - ); - - useEffect(() => { - if (!selection) { - retainedModelRef.current = null; - if (enabled && isExplorerActive) { - showMobileAgent(); - } - return; - } - if (!isExplorerActive) { - retainedModelRef.current = null; - return; - } - if (resolvedModel) { - retainedModelRef.current = resolvedModel; - } - }, [enabled, isExplorerActive, resolvedModel, selection, showMobileAgent]); - - return selection ? (resolvedModel ?? (isExplorerActive ? retainedModelRef.current : null)) : null; -} - -interface CompactExplorerSidebarHostProps { - children: ReactNode; - enabled: boolean; - presentation: "overlay" | "dock"; -} - -export function CompactExplorerSidebarHost({ - children, - enabled, - presentation, -}: CompactExplorerSidebarHostProps) { - const model = useActiveCompactExplorerSidebarModel(enabled); - const [containerWidth, setContainerWidth] = useState(0); - const openCompactFileExplorer = usePanelStore((state) => state.openCompactFileExplorer); - const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const openTab = useWorkspaceLayoutStore((state) => state.openTab); - const openWorkspaceTabInFocusedPane = useCallback( - (workspaceKey: string, target: WorkspaceTabTarget) => - openTab({ workspaceKey, target, intent: "reveal" }), - [openTab], - ); - const focusWorkspaceTab = useWorkspaceLayoutStore((state) => state.focusTab); - - const handleOpenExplorer = useCallback(() => { - if (!model?.workspaceRoot) { - return; - } - openCompactFileExplorer({ - serverId: model.serverId, - cwd: model.workspaceRoot, - isGit: model.isGit, - }); - }, [model, openCompactFileExplorer]); - - const handleOpenFile = useCallback( - (filePath: string) => { - if (!model) { - return; - } - openWorkspaceFileFromExplorer({ - filePath, - persistenceKey: model.persistenceKey, - closeExplorerAfterOpen: presentation === "overlay", - showMobileAgent, - openWorkspaceTabInFocusedPane, - focusWorkspaceTab, - }); - }, - [focusWorkspaceTab, model, openWorkspaceTabInFocusedPane, presentation, showMobileAgent], - ); - - const handleContainerLayout = useCallback((event: LayoutChangeEvent) => { - const nextWidth = event.nativeEvent.layout.width; - setContainerWidth((current) => (current === nextWidth ? current : nextWidth)); - }, []); - - const explorer = - enabled && model ? ( - - {presentation === "dock" ? ( - - ) : ( - - )} - - ) : null; - - let themedExplorer = explorer; - if (isWeb) { - themedExplorer = {explorer}; - } - - if (presentation === "dock") { - return ( - - {children} - {themedExplorer} - - ); - } - - return ( - <> - - {children} - - {themedExplorer} - - ); -} - -const styles = { - fill: { - flex: 1, - }, - row: { - flex: 1, - flexDirection: "row", - }, -} as const; diff --git a/packages/app/src/components/compact-explorer-sidebar.tsx b/packages/app/src/components/compact-explorer-sidebar.tsx deleted file mode 100644 index d52a9eac36..0000000000 --- a/packages/app/src/components/compact-explorer-sidebar.tsx +++ /dev/null @@ -1,574 +0,0 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import { View, Text, Pressable } from "react-native"; -import { Gesture } from "react-native-gesture-handler"; -import Animated, { runOnJS, useAnimatedStyle, useSharedValue } from "react-native-reanimated"; -import { scheduleOnRN } from "react-native-worklets"; -import { useSafeAreaInsets } from "react-native-safe-area-context"; -import { StyleSheet, useUnistyles, withUnistyles } from "react-native-unistyles"; -import { X } from "lucide-react-native"; -import { useTranslation } from "react-i18next"; -import { formatPrTabLabel, PullRequestTabIcon } from "@/git/pull-request-panel"; -import { - usePanelStore, - selectIsCompactFileExplorerOpen, - type ExplorerTab, -} from "@/stores/panel-store"; -import { useCloseFileExplorerGesture } from "@/mobile-panels/gestures"; -import { useIsMobilePanelActive } from "@/mobile-panels/provider"; -import { MobilePanelOverlay } from "@/mobile-panels/presentation"; -import { - HEADER_INNER_HEIGHT, - HEADER_INNER_HEIGHT_MOBILE, - HEADER_TOP_PADDING_MOBILE, - useIsCompactFormFactor, -} from "@/constants/layout"; -import { ChangesSurface } from "@/git/diff-pane"; -import { changesStateSchema, defaultChangesState, type ChangesState } from "@/panels/changes/state"; -import { FileExplorerPane } from "./file-explorer-pane"; -import { useKeyboardShiftStyle } from "@/keyboard/shift"; -import { shouldUseCompactExplorerKeyboardPadding } from "@/keyboard/shift"; -import { WindowChromeSafeArea } from "@/utils/desktop-window"; -import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region"; -import { RetainedPanel, RetainedPanelActivity } from "@/components/retained-panel"; -import { useMountedTabSet } from "@/screens/workspace/use-mounted-tab-set"; -import { usePullRequestPanelAvailability } from "@/panels/pull-request-availability"; -import { PullRequestContent } from "@/panels/pull-request"; -import { useAddFileToChat } from "@/panels/use-add-file-to-chat"; -import { SidebarResizeHandle } from "@/components/sidebar-resize-handle"; -import { - SIDEBAR_RESIZE_ACTIVATION_OFFSET, - SIDEBAR_RESIZE_FAIL_OFFSET, -} from "@/components/sidebar-resize-handle-layout"; -import { - EXPLORER_TAB_RAIL_INSET, - explorerSidebarCloseButtonLayout, - resolveExplorerSidebarWidth, -} from "@/components/explorer-sidebar-layout"; -import { ToolbarButton } from "@/components/ui/pane-content-toolbar"; -import { mutedIconColorMapping } from "@/components/ui/icon-button-chrome"; -import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; - -const ThemedX = withUnistyles(X); - -function logExplorerSidebar(_event: string, _details: Record): void {} - -interface ExplorerSidebarProps { - serverId: string; - workspaceId?: string | null; - workspaceRoot: string; - isGit: boolean; - onOpenFile?: (filePath: string) => void; -} - -interface ExplorerSidebarSharedState { - explorerTab: ExplorerTab; - handleTabPress: (tab: ExplorerTab) => void; -} - -function useExplorerSidebarSharedState({ - serverId, - workspaceRoot, - isGit, -}: Pick): ExplorerSidebarSharedState { - const explorerTab = usePanelStore((state) => state.explorerTab); - const setExplorerTabForCheckout = usePanelStore((state) => state.setExplorerTabForCheckout); - const handleTabPress = useCallback( - (tab: ExplorerTab) => { - setExplorerTabForCheckout({ serverId, cwd: workspaceRoot, isGit, tab }); - }, - [isGit, serverId, setExplorerTabForCheckout, workspaceRoot], - ); - - return { explorerTab, handleTabPress }; -} - -export function CompactExplorerSidebar({ - serverId, - workspaceId, - workspaceRoot, - isGit, - onOpenFile, -}: ExplorerSidebarProps) { - const { theme } = useUnistyles(); - const insets = useSafeAreaInsets(); - const isActive = useIsMobilePanelActive("file-explorer"); - const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const { explorerTab, handleTabPress } = useExplorerSidebarSharedState({ - serverId, - workspaceRoot, - isGit, - }); - const usePanelKeyboardPadding = shouldUseCompactExplorerKeyboardPadding({ isGit, explorerTab }); - const { style: mobileKeyboardInsetStyle } = useKeyboardShiftStyle({ - mode: "padding", - enabled: usePanelKeyboardPadding, - }); - const { gesture: closeGesture } = useCloseFileExplorerGesture(); - - const handleClose = useCallback( - (reason: string) => { - logExplorerSidebar("handleClose", { - reason, - isOpen: isActive, - }); - showMobileAgent(); - }, - [isActive, showMobileAgent], - ); - - const handleHeaderClose = useCallback(() => handleClose("header-close-button"), [handleClose]); - - const mobileSidebarStyle = useMemo( - () => [ - { - paddingTop: insets.top + HEADER_TOP_PADDING_MOBILE, - paddingBottom: usePanelKeyboardPadding ? 0 : insets.bottom, - backgroundColor: theme.colors.surfaceSidebar, - }, - mobileKeyboardInsetStyle, - ], - [ - insets.bottom, - insets.top, - mobileKeyboardInsetStyle, - theme.colors.surfaceSidebar, - usePanelKeyboardPadding, - ], - ); - - return ( - - - - - - ); -} - -interface NativeExplorerSidebarDockProps extends ExplorerSidebarProps { - persistenceKey: string; - containerWidth: number; -} - -export function NativeExplorerSidebarDock({ - serverId, - workspaceId, - workspaceRoot, - isGit, - onOpenFile, - persistenceKey, - containerWidth, -}: NativeExplorerSidebarDockProps) { - const { theme } = useUnistyles(); - const insets = useSafeAreaInsets(); - const isOpen = usePanelStore(selectIsCompactFileExplorerOpen); - const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const storedWidth = useWorkspaceLayoutStore( - (state) => state.explorerSidebarWidthByWorkspace[persistenceKey], - ); - const resizeExplorerSidebar = useWorkspaceLayoutStore((state) => state.resizeExplorerSidebar); - const visibleWidth = resolveExplorerSidebarWidth({ - requestedWidth: storedWidth, - containerWidth, - }); - const resizeWidth = useSharedValue(visibleWidth); - const startWidthRef = useRef(visibleWidth); - const [resizePressed, setResizePressed] = useState(false); - const { explorerTab, handleTabPress } = useExplorerSidebarSharedState({ - serverId, - workspaceRoot, - isGit, - }); - - useEffect(() => { - resizeWidth.value = visibleWidth; - }, [resizeWidth, visibleWidth]); - - const showResizeGrip = useCallback(() => setResizePressed(true), []); - const hideResizeGrip = useCallback(() => setResizePressed(false), []); - const commitWidth = useCallback( - (width: number) => resizeExplorerSidebar(persistenceKey, width), - [persistenceKey, resizeExplorerSidebar], - ); - const resizeGesture = useMemo( - () => - Gesture.Pan() - .enabled(true) - .hitSlop({ left: 8, right: 8, top: 0, bottom: 0 }) - .onBegin(() => scheduleOnRN(showResizeGrip)) - .activeOffsetX([-SIDEBAR_RESIZE_ACTIVATION_OFFSET, SIDEBAR_RESIZE_ACTIVATION_OFFSET]) - .failOffsetY([-SIDEBAR_RESIZE_FAIL_OFFSET, SIDEBAR_RESIZE_FAIL_OFFSET]) - .onStart((event) => { - startWidthRef.current = visibleWidth + event.translationX; - resizeWidth.value = visibleWidth; - }) - .onUpdate((event) => { - resizeWidth.value = resolveExplorerSidebarWidth({ - requestedWidth: startWidthRef.current - event.translationX, - containerWidth, - }); - }) - .onEnd(() => runOnJS(commitWidth)(resizeWidth.value)) - .onFinalize(() => scheduleOnRN(hideResizeGrip)), - [commitWidth, containerWidth, hideResizeGrip, resizeWidth, showResizeGrip, visibleWidth], - ); - const animatedWidthStyle = useAnimatedStyle(() => ({ width: resizeWidth.value })); - const dockStyle = useMemo( - () => [ - styles.nativeDock, - { - display: isOpen ? ("flex" as const) : ("none" as const), - paddingTop: insets.top + HEADER_TOP_PADDING_MOBILE, - backgroundColor: theme.colors.surfaceSidebar, - }, - animatedWidthStyle, - ], - [animatedWidthStyle, insets.top, isOpen, theme.colors.surfaceSidebar], - ); - const dockContentStyle = useMemo( - () => [styles.nativeDockContent, { borderLeftColor: theme.colors.border }], - [theme.colors.border], - ); - - return ( - - - - - - - - - ); -} - -interface ExplorerTabButtonProps { - tab: ExplorerTab; - active: boolean; - label?: string; - onTabPress: (tab: ExplorerTab) => void; - testID: string; - children?: React.ReactNode; -} - -function ExplorerTabButton({ - tab, - active, - label, - onTabPress, - testID, - children, -}: ExplorerTabButtonProps) { - const isCompact = useIsCompactFormFactor(); - const handlePress = useCallback(() => onTabPress(tab), [onTabPress, tab]); - const tabStyle = useMemo( - () => [styles.tab(isCompact), active && styles.tabActive], - [active, isCompact], - ); - const tabTextStyle = useMemo(() => [styles.tabText, active && styles.tabTextActive], [active]); - return ( - - {children} - {label !== undefined ? {label} : null} - - ); -} - -interface SidebarContentProps { - activeTab: ExplorerTab; - onTabPress: (tab: ExplorerTab) => void; - onClose: () => void; - serverId: string; - workspaceId?: string | null; - workspaceRoot: string; - isGit: boolean; - isOpen: boolean; - onOpenFile?: (filePath: string) => void; -} - -function ExplorerSidebarContent({ - activeTab, - onTabPress, - onClose, - serverId, - workspaceId, - workspaceRoot, - isGit, - isOpen, - onOpenFile, -}: SidebarContentProps) { - const { theme } = useUnistyles(); - const { t } = useTranslation(); - const isCompact = useIsCompactFormFactor(); - const closeButtonLayout = explorerSidebarCloseButtonLayout(isCompact); - const closeButtonStyle = useMemo( - () => ({ width: closeButtonLayout.size, height: closeButtonLayout.size }), - [closeButtonLayout.size], - ); - // The close glyph shares the trailing rail with the toolbar rows below it. - const headerRightSectionStyle = useMemo( - () => [styles.headerRightSection, { paddingRight: closeButtonLayout.trailingPadding }], - [closeButtonLayout.trailingPadding], - ); - const { prPane, showPullRequest: showPrTab } = usePullRequestPanelAvailability({ - serverId, - cwd: workspaceRoot, - isGit, - requested: activeTab === "pr", - enabled: isOpen, - timelineEnabled: activeTab === "pr", - }); - const requestedTab: ExplorerTab = - !isGit && (activeTab === "changes" || activeTab === "pr") ? "files" : activeTab; - const resolvedTab: ExplorerTab = requestedTab === "pr" && !showPrTab ? "changes" : requestedTab; - const prTabLabel = formatPrTabLabel(prPane.prNumber); - const availableTabs = useMemo(() => { - const tabs: ExplorerTab[] = isGit ? ["changes", "files"] : ["files"]; - if (isGit && showPrTab) tabs.push("pr"); - return tabs; - }, [isGit, showPrTab]); - const { mountedTabIds } = useMountedTabSet({ - activeTabId: resolvedTab, - allTabIds: availableTabs, - cap: availableTabs.length, - }); - - return ( - - {/* Header with tabs and close button */} - - - - {isGit && ( - - )} - - {isGit && showPrTab && ( - - - - )} - - - - - - - - - {/* Content based on active tab */} - - {mountedTabIds.has("changes") ? ( - - - - ) : null} - {mountedTabIds.has("files") ? ( - - - - ) : null} - {mountedTabIds.has("pr") ? ( - - - - ) : null} - - - ); -} - -function ChangedFilesPane({ - serverId, - workspaceId, - workspaceRoot, - isOpen, - onOpenFile, -}: Pick< - SidebarContentProps, - "serverId" | "workspaceId" | "workspaceRoot" | "isOpen" | "onOpenFile" ->) { - const { addFile, canAddToChat } = useAddFileToChat({ serverId, workspaceId }); - const [changesState, setChangesState] = useState(() => - changesStateSchema.parse(defaultChangesState), - ); - return ( - - ); -} - -function FilesPane({ - serverId, - workspaceId, - workspaceRoot, - onOpenFile, -}: Pick) { - const { addFile, canAddToChat } = useAddFileToChat({ serverId, workspaceId }); - return ( - - ); -} - -const PrTabContent = PullRequestContent; - -const styles = StyleSheet.create((theme) => ({ - nativeDock: { - position: "relative", - height: "100%", - minHeight: 0, - overflow: "hidden", - }, - nativeDockContent: { - position: "relative", - flex: 1, - minHeight: 0, - borderLeftWidth: 1, - }, - sidebarContent: { - flex: 1, - minHeight: 0, - overflow: "hidden", - }, - header: { - position: "relative", - height: { - xs: HEADER_INNER_HEIGHT_MOBILE, - md: HEADER_INNER_HEIGHT, - }, - flexDirection: "row", - alignItems: "center", - justifyContent: "space-between", - borderBottomWidth: 1, - borderBottomColor: theme.colors.border, - }, - tabsContainer: (isCompact: boolean) => ({ - flexDirection: "row", - gap: theme.spacing[1], - // With the tab's own horizontal padding this puts the label on the pane's - // leading rail, the same way the desktop tab rail does. - paddingLeft: isCompact ? EXPLORER_TAB_RAIL_INSET : theme.spacing[2], - }), - tab: (isCompact: boolean) => ({ - flexDirection: "row", - alignItems: "center", - gap: theme.spacing[2], - paddingVertical: theme.spacing[2], - paddingHorizontal: isCompact ? theme.spacing[2] : theme.spacing[3], - borderRadius: theme.borderRadius.md, - }), - tabActive: { - backgroundColor: theme.colors.surfaceSidebarHover, - }, - tabText: { - fontSize: theme.fontSize.base, - fontWeight: theme.fontWeight.normal, - color: theme.colors.foregroundMuted, - }, - tabTextActive: { - color: theme.colors.foreground, - }, - tabTextMuted: { - opacity: 0.8, - }, - headerRightSection: { - flexDirection: "row", - alignItems: "center", - gap: theme.spacing[2], - }, - contentArea: { - flex: 1, - minHeight: 0, - }, -})); diff --git a/packages/app/src/components/desktop-sidebar-layout.test.ts b/packages/app/src/components/desktop-sidebar-layout.test.ts index 87b5e9583f..969bbb581f 100644 --- a/packages/app/src/components/desktop-sidebar-layout.test.ts +++ b/packages/app/src/components/desktop-sidebar-layout.test.ts @@ -101,3 +101,25 @@ describe("desktop sidebar layout", () => { ).toBe(true); }); }); + +it("reserves room for Explorer and the workspace before showing app navigation", () => { + const contentMinimumWidth = resolveDesktopAppContentMinimum({ + isSettingsRoute: false, + explorerVisible: true, + }); + expect(contentMinimumWidth).toBe(600); + expect( + canDesktopAppSidebarShare({ + contentMinimumWidth, + requestedSidebarWidth: 320, + viewportWidth: 744, + }), + ).toBe(false); + expect( + canDesktopAppSidebarShare({ + contentMinimumWidth, + requestedSidebarWidth: 320, + viewportWidth: 951, + }), + ).toBe(true); +}); diff --git a/packages/app/src/components/desktop-sidebar-layout.ts b/packages/app/src/components/desktop-sidebar-layout.ts index ff58bc8025..d8518bcb82 100644 --- a/packages/app/src/components/desktop-sidebar-layout.ts +++ b/packages/app/src/components/desktop-sidebar-layout.ts @@ -1,3 +1,4 @@ +import { EXPLORER_WORKSPACE_MIN_WIDTH } from "@/components/explorer-sidebar-layout"; import { SETTINGS_DESKTOP_SPLIT_MIN_WIDTH } from "@/constants/layout"; import { MAX_SIDEBAR_WIDTH, MIN_SIDEBAR_WIDTH } from "@/stores/panel-store"; @@ -62,8 +63,12 @@ export function resolveDesktopSidebarWidth(input: { }); } -export function resolveDesktopAppContentMinimum(input: { isSettingsRoute: boolean }): number { - return input.isSettingsRoute ? SETTINGS_DESKTOP_SPLIT_MIN_WIDTH : 0; +export function resolveDesktopAppContentMinimum(input: { + isSettingsRoute: boolean; + explorerVisible?: boolean; +}): number { + if (input.isSettingsRoute) return SETTINGS_DESKTOP_SPLIT_MIN_WIDTH; + return input.explorerVisible ? EXPLORER_WORKSPACE_MIN_WIDTH : 0; } export function canDesktopAppSidebarShare(input: { diff --git a/packages/app/src/components/explorer-sidebar-layout.test.ts b/packages/app/src/components/explorer-sidebar-layout.test.ts index 0570144000..3681ad4e16 100644 --- a/packages/app/src/components/explorer-sidebar-layout.test.ts +++ b/packages/app/src/components/explorer-sidebar-layout.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from "vitest"; import { - explorerSidebarCloseButtonLayout, resolveExplorerSidebarDockSizes, resolveExplorerSidebarWidth, } from "@/components/explorer-sidebar-layout"; @@ -17,24 +16,7 @@ describe("Explorer sidebar layout", () => { it("has no fixed maximum while preserving room for the workspace body", () => { expect(resolveExplorerSidebarWidth({ requestedWidth: 100, containerWidth: 1200 })).toBe(240); expect(resolveExplorerSidebarWidth({ requestedWidth: 900, containerWidth: 1600 })).toBe(900); - expect(resolveExplorerSidebarWidth({ requestedWidth: 900, containerWidth: 1200 })).toBe(800); - expect(resolveExplorerSidebarWidth({ requestedWidth: 600, containerWidth: 750 })).toBe(350); - }); -}); - -describe("Explorer close action", () => { - it("preserves the wide-native touch target and glyph rail", () => { - const layout = explorerSidebarCloseButtonLayout(false); - expect(layout.size).toBe(34); - expect(layout.iconSize).toBe(18); - expect(layout.size + layout.hitSlop * 2).toBe(50); - expect(layout.trailingPadding + (layout.size - layout.iconSize) / 2).toBe(16); - }); - - it("keeps the compact close glyph on the pane rail", () => { - const layout = explorerSidebarCloseButtonLayout(true); - expect(layout.size).toBe(32); - expect(layout.iconSize).toBe(18); - expect(layout.trailingPadding + (layout.size - layout.iconSize) / 2).toBe(8); + expect(resolveExplorerSidebarWidth({ requestedWidth: 900, containerWidth: 1200 })).toBe(840); + expect(resolveExplorerSidebarWidth({ requestedWidth: 600, containerWidth: 750 })).toBe(390); }); }); diff --git a/packages/app/src/components/explorer-sidebar-layout.ts b/packages/app/src/components/explorer-sidebar-layout.ts index 5cd5352556..8a39e2e9f4 100644 --- a/packages/app/src/components/explorer-sidebar-layout.ts +++ b/packages/app/src/components/explorer-sidebar-layout.ts @@ -1,36 +1,13 @@ -import { - paneContentToolbarIconSize, - paneContentToolbarTrailingPadding, -} from "@/components/ui/pane-content-toolbar"; -import { smallIconButtonChromeFrameSize } from "@/components/ui/icon-button-chrome"; - -export function explorerSidebarCloseButtonLayout(compact: boolean) { - // The inline native dock retains its padded close action and touch slop. - if (!compact) { - return { size: 34, iconSize: 18, hitSlop: 8, trailingPadding: 8 }; - } - return { - size: smallIconButtonChromeFrameSize(compact), - iconSize: paneContentToolbarIconSize(compact), - hitSlop: 0, - trailingPadding: paneContentToolbarTrailingPadding(compact, "glyph"), - }; -} - -/** - * Outer inset of an Explorer tab rail. With each tab's own horizontal padding it puts - * the tab label on the pane's shared leading rail (`treeRowPaddingLeft(0)`). - */ -export const EXPLORER_TAB_RAIL_INSET = 4; - const DEFAULT_EXPLORER_SIDEBAR_WIDTH = 320; const MIN_EXPLORER_SIDEBAR_WIDTH = 240; -const MIN_WORKSPACE_BODY_WIDTH = 400; +const MIN_WORKSPACE_BODY_WIDTH = 360; +export const EXPLORER_WORKSPACE_MIN_WIDTH = MIN_EXPLORER_SIDEBAR_WIDTH + MIN_WORKSPACE_BODY_WIDTH; export function resolveExplorerSidebarWidth(input: { requestedWidth?: number; containerWidth: number; }): number { + "worklet"; const requestedWidth = input.requestedWidth ?? DEFAULT_EXPLORER_SIDEBAR_WIDTH; const maximumVisibleWidth = input.containerWidth > 0 diff --git a/packages/app/src/components/file-drop/file-drop-backdrop.tsx b/packages/app/src/components/file-drop/file-drop-backdrop.tsx index b661dbe49a..bafc9c0227 100644 --- a/packages/app/src/components/file-drop/file-drop-backdrop.tsx +++ b/packages/app/src/components/file-drop/file-drop-backdrop.tsx @@ -46,7 +46,7 @@ export function FileDropBackdrop() { const positionStyles = RNStyleSheet.create({ overlay: { - ...RNStyleSheet.absoluteFillObject, + ...RNStyleSheet.absoluteFill, alignItems: "center", justifyContent: "center", zIndex: 1000, @@ -55,7 +55,7 @@ const positionStyles = RNStyleSheet.create({ const styles = StyleSheet.create((theme) => ({ backdrop: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, backgroundColor: theme.colors.surface0, opacity: 0.7, }, diff --git a/packages/app/src/components/headers/compact-header.tsx b/packages/app/src/components/headers/compact-header.tsx index 6ed2bddcbe..cbc161ae66 100644 --- a/packages/app/src/components/headers/compact-header.tsx +++ b/packages/app/src/components/headers/compact-header.tsx @@ -52,8 +52,15 @@ export function CompactHeader({ }: CompactHeaderProps) { const insets = useSafeAreaInsets(); const rootStyle = useMemo( - () => [styles.root, { paddingTop: insets.top + HEADER_TOP_PADDING_MOBILE }], - [insets.top], + () => [ + styles.root, + { + paddingTop: insets.top + HEADER_TOP_PADDING_MOBILE, + marginLeft: insets.left, + marginRight: insets.right, + }, + ], + [insets.top, insets.left, insets.right], ); return ( diff --git a/packages/app/src/components/left-sidebar.tsx b/packages/app/src/components/left-sidebar.tsx index 58d0dee053..6cf9e29eb1 100644 --- a/packages/app/src/components/left-sidebar.tsx +++ b/packages/app/src/components/left-sidebar.tsx @@ -679,7 +679,9 @@ function DesktopSidebar({ const hasActiveHostFilter = useSidebarViewStore((state) => state.hostFilters.length > 0); const sidebarWidth = usePanelStore((state) => state.sidebarWidth); const setSidebarWidth = usePanelStore((state) => state.setSidebarWidth); - const { width: viewportWidth } = useWindowDimensions(); + const { width: windowWidth } = useWindowDimensions(); + const insets = useSafeAreaInsets(); + const viewportWidth = windowWidth - insets.left - insets.right; const visibleSidebarWidth = resolveDesktopSidebarWidth({ requestedWidth: sidebarWidth, viewportWidth, diff --git a/packages/app/src/components/sidebar-workspace-list.tsx b/packages/app/src/components/sidebar-workspace-list.tsx index 9ce91b5a10..74d57ca667 100644 --- a/packages/app/src/components/sidebar-workspace-list.tsx +++ b/packages/app/src/components/sidebar-workspace-list.tsx @@ -2761,7 +2761,7 @@ const styles = StyleSheet.create((theme) => ({ justifyContent: "center", }, workspaceArchivingOverlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, borderRadius: theme.borderRadius.lg, backgroundColor: `${theme.colors.surface0}cc`, alignItems: "center", diff --git a/packages/app/src/components/split-container.tsx b/packages/app/src/components/split-container.tsx index c6d95f40b7..660b5f4e6b 100644 --- a/packages/app/src/components/split-container.tsx +++ b/packages/app/src/components/split-container.tsx @@ -1,3 +1,4 @@ +import { useWorkspaceTabDrag } from "./workspace-tab-drag-context"; import { Fragment, memo, @@ -11,35 +12,14 @@ import { type SetStateAction, } from "react"; import { useStableEvent } from "@/hooks/use-stable-event"; -import { - DndContext, - DragOverlay, - KeyboardSensor, - PointerSensor, - closestCenter, - pointerWithin, - useSensor, - useSensors, - type CollisionDetection, - type DragEndEvent, - type DragMoveEvent, - type DragOverEvent, - type DragStartEvent, -} from "@dnd-kit/core"; -import { arrayMove, sortableKeyboardCoordinates } from "@dnd-kit/sortable"; -import { View, Text, type LayoutChangeEvent } from "react-native"; +import { View, type LayoutChangeEvent } from "react-native"; import Animated, { useAnimatedStyle, useSharedValue, type SharedValue, } from "react-native-reanimated"; -import { useTranslation } from "react-i18next"; -import { StyleSheet, useUnistyles } from "react-native-unistyles"; +import { StyleSheet } from "react-native-unistyles"; import { ResizeHandle } from "@/components/resize-handle"; -import { - resolveExplorerSidebarDockSizes, - resolveExplorerSidebarWidth, -} from "@/components/explorer-sidebar-layout"; import { RetainedPanel } from "@/components/retained-panel"; import { hasMultipleVisiblePanes, @@ -48,41 +28,26 @@ import { } from "@/components/split-container-focus"; import { shouldFocusPaneFromEventTarget } from "@/components/split-container-pane-focus"; import { - removeWindowChromeCorner, WindowChromeRegion, WindowChromeSafeArea, useWindowChromeCorners, + removeWindowChromeCorner, type WindowChromeCorners, } from "@/utils/desktop-window"; import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region"; -import { - computeTabDropPreview, - type TabDropPreview, -} from "@/components/split-container-tab-drop-preview"; -import { - SplitDropZone, - resolveSplitDropPosition, - type SplitDropZoneHover, -} from "@/components/split-drop-zone"; -import { - deriveWorkspacePaneState, - getWorkspacePaneDescriptors, -} from "@/screens/workspace/workspace-pane-state"; +import { type TabDropPreview } from "@/components/split-container-tab-drop-preview"; +import { SplitDropZone, type SplitDropZoneHover } from "@/components/split-drop-zone"; +import { deriveWorkspacePaneState } from "@/screens/workspace/workspace-pane-state"; import type { WorkspacePaneContentModel } from "@/screens/workspace/workspace-pane-content"; import { WorkspacePanelHost } from "@/screens/workspace/workspace-panel-host"; import { WorkspaceDesktopTabsRow, type WorkspaceDesktopTabRowItem, } from "@/screens/workspace/workspace-desktop-tabs-row"; -import { ExplorerSidebarDock } from "@/screens/workspace/explorer-sidebar"; -import { - WorkspaceTabPresentationResolver, - WorkspaceTabIcon, -} from "@/screens/workspace/workspace-tab-presentation"; import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types"; import { + collectAllPanes, createDefaultLayout, - findPaneById, useWorkspaceLayoutStore, type SplitNode, type SplitPane, @@ -90,14 +55,11 @@ import { } from "@/stores/workspace-layout-store"; import type { WorkspaceTab } from "@/workspace-tabs/model"; import { recordRenderProfileReasons, RenderProfile } from "@/utils/render-profiler"; -import { inlineUnistylesStyle } from "@/styles/unistyles-inline-style"; import { isNative } from "@/constants/platform"; -import { panelTargetSupportsHost } from "@/plugins/workspace-panels/locations"; interface SplitContainerProps { layout: WorkspaceLayout; renderMainHeader?: () => ReactNode; - renderExplorerSidebarHeaderAction?: () => ReactNode; workspaceKey: string; normalizedServerId: string; normalizedWorkspaceId: string; @@ -140,41 +102,6 @@ interface SplitContainerProps { onExitFocusMode: () => void; } -interface WorkspaceTabDragData { - kind: "workspace-tab"; - paneId: string; - tabId: string; -} - -interface SplitPaneDropData { - kind: "split-pane-drop"; - paneId: string; -} - -const EMPTY_SPLIT_NODES: SplitNode[] = []; -const EMPTY_SPLIT_SIZES: number[] = []; -const EXPLORER_SIDEBAR_RESIZE_GROUP_ID = "explorer-sidebar"; - -function isWorkspaceTabDragData(data: unknown): data is WorkspaceTabDragData { - return typeof data === "object" && data !== null && Reflect.get(data, "kind") === "workspace-tab"; -} - -function isSplitPaneDropData(data: unknown): data is SplitPaneDropData { - return ( - typeof data === "object" && data !== null && Reflect.get(data, "kind") === "split-pane-drop" - ); -} - -function asWorkspaceTabDragData(data: unknown): WorkspaceTabDragData | undefined { - return isWorkspaceTabDragData(data) ? data : undefined; -} - -function asDragOverData(data: unknown): WorkspaceTabDragData | SplitPaneDropData | undefined { - if (isWorkspaceTabDragData(data)) return data; - if (isSplitPaneDropData(data)) return data; - return undefined; -} - interface SplitNodeViewProps extends Omit< SplitContainerProps, "layout" | "onMoveTabToPane" | "onSelectTabInPane" @@ -212,105 +139,12 @@ interface SplitPaneViewProps extends Omit< tabDropPreview: TabDropPreview | null; } -interface DragMoveRects { - translatedRect: { left: number; top: number; width: number; height: number }; - overRect: { left: number; top: number; width: number; height: number }; -} - -function resolveDragMoveRects( - event: Pick | Pick, -): DragMoveRects | null { - const translatedRect = event.active.rect.current.translated; - const overRect = event.over?.rect; - if (!translatedRect || !overRect || overRect.width <= 0 || overRect.height <= 0) { - return null; - } - return { translatedRect, overRect }; -} - -function computeTabOverDropPreview(input: { - activeData: WorkspaceTabDragData; - overData: WorkspaceTabDragData; - rects: DragMoveRects; - panesById: Map; - uiTabs: WorkspaceTab[]; -}): TabDropPreview | null { - const { activeData, overData, rects, panesById, uiTabs } = input; - const targetPane = panesById.get(overData.paneId) ?? null; - if (!targetPane) { - return null; - } - const targetTabs = getWorkspacePaneDescriptors({ pane: targetPane, tabs: uiTabs }); - return computeTabDropPreview({ - activePaneId: activeData.paneId, - activeTabId: activeData.tabId, - overPaneId: overData.paneId, - overTabId: overData.tabId, - targetTabs, - activeRect: { - left: rects.translatedRect.left, - width: rects.translatedRect.width, - }, - overRect: { - left: rects.overRect.left, - width: rects.overRect.width, - }, - }); -} - -function computePaneOverDropPreview(input: { - overData: SplitPaneDropData; - rects: DragMoveRects; -}): SplitDropZoneHover | null { - const { overData, rects } = input; - const centerX = rects.translatedRect.left + rects.translatedRect.width / 2; - const centerY = rects.translatedRect.top + rects.translatedRect.height / 2; - const relativeX = centerX - rects.overRect.left; - const relativeY = centerY - rects.overRect.top; - if ( - Number.isNaN(relativeX) || - Number.isNaN(relativeY) || - relativeX < 0 || - relativeX > rects.overRect.width || - relativeY < 0 || - relativeY > rects.overRect.height - ) { - return null; - } - return { - paneId: overData.paneId, - position: resolveSplitDropPosition({ - width: rects.overRect.width, - height: rects.overRect.height, - x: relativeX, - y: relativeY, - }), - }; -} - -const dropCollisionDetection: CollisionDetection = (args) => { - const pointerHits = pointerWithin(args); - const tabHits = pointerHits.filter( - (entry) => entry.data?.droppableContainer.data.current?.kind === "workspace-tab", - ); - if (tabHits.length > 0) { - return tabHits; - } - - const paneHits = pointerHits.filter( - (entry) => entry.data?.droppableContainer.data.current?.kind === "split-pane-drop", - ); - if (paneHits.length > 0) { - return paneHits; - } - - return closestCenter(args); -}; +const EMPTY_SPLIT_NODES: SplitNode[] = []; +const EMPTY_SPLIT_SIZES: number[] = []; export function SplitContainer({ layout, renderMainHeader, - renderExplorerSidebarHeaderAction, workspaceKey, normalizedServerId, normalizedWorkspaceId, @@ -335,8 +169,6 @@ export function SplitContainer({ onFocusPane, onSplitPane, onSplitPaneEmpty, - onMoveTabToPane, - onSelectTabInPane, onResizeSplit, onReorderTabsInPane, focusModeEnabled, @@ -344,9 +176,7 @@ export function SplitContainer({ }: SplitContainerProps) { const inheritedWindowChromeCorners = useWindowChromeCorners(); const windowChromeCorners = focusModeEnabled ? inheritedWindowChromeCorners : "none"; - const [activeDragTabId, setActiveDragTabId] = useState(null); - const [dropPreview, setDropPreview] = useState(null); - const [tabDropPreview, setTabDropPreview] = useState(null); + const { activeDragTabId, dropPreview, tabDropPreview } = useWorkspaceTabDrag(); const [maximizedPane, setMaximizedPane] = useState<{ workspaceKey: string; paneId: string; @@ -357,22 +187,6 @@ export function SplitContainer({ (state) => state.explorerSidebarPaneIdByWorkspace[workspaceKey] ?? null, ); - const sensors = useSensors( - useSensor(PointerSensor, { - activationConstraint: { - distance: 8, - }, - }), - useSensor(KeyboardSensor, { - coordinateGetter: sortableKeyboardCoordinates, - }), - ); - - const panesById = useMemo(() => collectPanesById(layout.root), [layout.root]); - const explorerSidebarPane = useMemo( - () => findPaneById(layout.root, explorerSidebarPaneId), - [layout.root, explorerSidebarPaneId], - ); const mainRoot = useMemo( () => removePaneFromSplitTree(layout.root, explorerSidebarPaneId), [layout.root, explorerSidebarPaneId], @@ -408,434 +222,68 @@ export function SplitContainer({ }), [focusModeEnabled, layout.focusedPaneId, mainRoot], ); - const storedExplorerSidebarWidth = useWorkspaceLayoutStore( - (state) => state.explorerSidebarWidthByWorkspace[workspaceKey], - ); - const resizeExplorerSidebar = useWorkspaceLayoutStore((state) => state.resizeExplorerSidebar); - const [workspaceShellWidth, setWorkspaceShellWidth] = useState(0); - const [previewExplorerSidebarWidth, setPreviewExplorerSidebarWidth] = useState( - null, - ); - const requestedExplorerSidebarWidth = previewExplorerSidebarWidth ?? storedExplorerSidebarWidth; - const explorerSidebarWidth = resolveExplorerSidebarWidth({ - requestedWidth: requestedExplorerSidebarWidth, - containerWidth: workspaceShellWidth, - }); - const explorerSidebarDockSizes = useMemo( - () => - resolveExplorerSidebarDockSizes({ - requestedWidth: requestedExplorerSidebarWidth, - containerWidth: workspaceShellWidth, - }), - [requestedExplorerSidebarWidth, workspaceShellWidth], - ); - const renderExplorerSidebarDock = Boolean( - !focusModeEnabled && explorerSidebarPane && explorerSidebarPane.hidden !== true, - ); - const mainColumnWindowChromeCorners = renderExplorerSidebarDock - ? removeWindowChromeCorner(inheritedWindowChromeCorners, "top-right") - : inheritedWindowChromeCorners; + const explorerPane = explorerSidebarPaneId + ? collectAllPanes(layout.root).find((pane) => pane.id === explorerSidebarPaneId) + : null; + const mainColumnWindowChromeCorners = + !focusModeEnabled && explorerPane && !explorerPane.hidden + ? removeWindowChromeCorner(inheritedWindowChromeCorners, "top-right") + : inheritedWindowChromeCorners; const mainColumnStyle = styles.mainColumn; - const explorerSidebarDockStyle = useMemo( - () => [styles.explorerSidebarDock, inlineUnistylesStyle({ width: explorerSidebarWidth })], - [explorerSidebarWidth], - ); - const handleWorkspaceShellLayout = useCallback((event: LayoutChangeEvent) => { - const nextWidth = event.nativeEvent.layout.width; - setWorkspaceShellWidth((current) => (current === nextWidth ? current : nextWidth)); - }, []); - const previewExplorerSidebarResize = useCallback( - (_groupId: string, sizes: number[]) => { - const nextRatio = sizes[1]; - if (nextRatio !== undefined) { - setPreviewExplorerSidebarWidth( - resolveExplorerSidebarWidth({ - requestedWidth: nextRatio * workspaceShellWidth, - containerWidth: workspaceShellWidth, - }), - ); - } - }, - [workspaceShellWidth], - ); - const commitExplorerSidebarResize = useCallback( - (_groupId: string, sizes: number[]) => { - setPreviewExplorerSidebarWidth(null); - const nextRatio = sizes[1]; - if (nextRatio !== undefined) { - resizeExplorerSidebar( - workspaceKey, - resolveExplorerSidebarWidth({ - requestedWidth: nextRatio * workspaceShellWidth, - containerWidth: workspaceShellWidth, - }), - ); - } - }, - [resizeExplorerSidebar, workspaceKey, workspaceShellWidth], - ); const renderRoot = useMemo(() => wrapRootPaneForStableMount(splitRoot.root), [splitRoot.root]); - const handleDragStart = useCallback((event: DragStartEvent) => { - const data = asWorkspaceTabDragData(event.active.data.current); - if (!data) { - setActiveDragTabId(null); - setDropPreview(null); - setTabDropPreview(null); - return; - } - setActiveDragTabId(data.tabId); - }, []); - - const handleDragCancel = useCallback(() => { - setActiveDragTabId(null); - setDropPreview(null); - setTabDropPreview(null); - }, []); - - const updateDropPreview = useCallback( - (event: Pick | Pick) => { - const activeData = asWorkspaceTabDragData(event.active.data.current); - const overData = asDragOverData(event.over?.data.current); - - if (activeData?.kind !== "workspace-tab") { - setDropPreview(null); - setTabDropPreview(null); - return; - } - - const rects = resolveDragMoveRects(event); - if (!rects) { - setDropPreview(null); - setTabDropPreview(null); - return; - } - - const activeTab = uiTabs.find((tab) => tab.tabId === activeData.tabId) ?? null; - const destinationPaneId = - overData?.kind === "workspace-tab" || overData?.kind === "split-pane-drop" - ? overData.paneId - : null; - const destinationHost = destinationPaneId === explorerSidebarPaneId ? "explorer" : "main"; - if ( - !activeTab || - !panelTargetSupportsHost(normalizedServerId, activeTab.target, destinationHost) - ) { - setDropPreview(null); - setTabDropPreview(null); - return; - } - - if (overData?.kind === "workspace-tab") { - const preview = computeTabOverDropPreview({ - activeData, - overData, - rects, - panesById, - uiTabs, - }); - setDropPreview(null); - setTabDropPreview(preview); - return; - } - - setTabDropPreview(null); - if (overData?.kind !== "split-pane-drop") { - setDropPreview(null); - return; - } - - setDropPreview(computePaneOverDropPreview({ overData, rects })); - }, - [normalizedServerId, panesById, explorerSidebarPaneId, uiTabs], - ); - - const applyTabDropEnd = useCallback( - (input: { activeData: WorkspaceTabDragData; overData: WorkspaceTabDragData }): void => { - const { activeData, overData } = input; - const sourcePane = panesById.get(activeData.paneId) ?? null; - const targetPane = panesById.get(overData.paneId) ?? null; - if (!sourcePane || !targetPane) { - return; - } - - const sourceTabs = getWorkspacePaneDescriptors({ pane: sourcePane, tabs: uiTabs }); - const targetTabs = getWorkspacePaneDescriptors({ pane: targetPane, tabs: uiTabs }); - const sourceIndex = sourceTabs.findIndex((tab) => tab.tabId === activeData.tabId); - const resolvedTabDropPreview = - tabDropPreview?.paneId === overData.paneId ? tabDropPreview : null; - if (sourceIndex < 0 || !resolvedTabDropPreview) { - return; - } - - if (activeData.paneId === overData.paneId) { - if (sourceIndex !== resolvedTabDropPreview.insertionIndex) { - const nextTabs = arrayMove( - sourceTabs, - sourceIndex, - resolvedTabDropPreview.insertionIndex, - ); - onReorderTabsInPane( - activeData.paneId, - nextTabs.map((tab) => tab.tabId), - ); - } - return; - } - - const nextTargetTabIds = targetTabs.map((tab) => tab.tabId); - nextTargetTabIds.splice(resolvedTabDropPreview.insertionIndex, 0, activeData.tabId); - onMoveTabToPane(activeData.tabId, overData.paneId); - onReorderTabsInPane(overData.paneId, nextTargetTabIds); - }, - [onMoveTabToPane, onReorderTabsInPane, panesById, tabDropPreview, uiTabs], - ); - - const applyPaneDropEnd = useCallback( - (input: { activeData: WorkspaceTabDragData; overData: SplitPaneDropData }): void => { - const { activeData, overData } = input; - if (dropPreview?.paneId !== overData.paneId) { - return; - } - if (dropPreview.position === "center") { - if (activeData.paneId !== overData.paneId) { - onMoveTabToPane(activeData.tabId, overData.paneId); - } - return; - } - onSplitPane({ - tabId: activeData.tabId, - targetPaneId: overData.paneId, - position: dropPreview.position, - }); - }, - [dropPreview, onMoveTabToPane, onSplitPane], - ); - - const handleDragEnd = useCallback( - (event: DragEndEvent) => { - const activeData = asWorkspaceTabDragData(event.active.data.current); - const overData = asDragOverData(event.over?.data.current); - - setActiveDragTabId(null); - - if (activeData?.kind === "workspace-tab" && event.over) { - if (overData?.kind === "workspace-tab") { - applyTabDropEnd({ activeData, overData }); - } else if (overData?.kind === "split-pane-drop") { - applyPaneDropEnd({ activeData, overData }); - } - } - - setDropPreview(null); - setTabDropPreview(null); - }, - [applyTabDropEnd, applyPaneDropEnd], - ); - return ( - - - - - {renderMainHeader?.()} - {splitRoot.usesFallbackStrip && } - {renderRoot ? ( - - ) : null} - - - {renderExplorerSidebarDock && explorerSidebarPane ? ( - <> - + + + {renderMainHeader?.()} + {splitRoot.usesFallbackStrip && } + {renderRoot ? ( + - - - - - ) : null} - - - {activeDragTabId ? ( - - ) : null} - - - - ); -} - -function DragOverlayTabChip({ - tabId, - uiTabs, - normalizedServerId, - normalizedWorkspaceId, -}: { - tabId: string; - uiTabs: WorkspaceTab[]; - normalizedServerId: string; - normalizedWorkspaceId: string; -}) { - const tab = uiTabs.find((t) => t.tabId === tabId); - const descriptor = useMemo( - () => - tab - ? { - key: tab.tabId, - tabId: tab.tabId, - kind: tab.target.kind, - target: tab.target, - } - : null, - [tab], - ); - if (!descriptor) { - return null; - } - return ( - - ); -} - -function DragOverlayTabChipInner({ - tab, - normalizedServerId, - normalizedWorkspaceId, -}: { - tab: WorkspaceTabDescriptor; - normalizedServerId: string; - normalizedWorkspaceId: string; -}) { - const { t } = useTranslation(); - const { theme } = useUnistyles(); - - const chipStyle = useMemo( - () => [ - styles.dragOverlayChip, - { - backgroundColor: theme.colors.surface1, - borderColor: theme.colors.borderAccent, - }, - ], - [theme.colors.surface1, theme.colors.borderAccent], - ); - const chipLabelStyle = useMemo( - () => [styles.dragOverlayLabel, { color: theme.colors.foreground }], - [theme.colors.foreground], - ); - - return ( - - {(presentation) => { - const label = - presentation.titleState === "loading" ? t("common.states.loading") : presentation.label; - - return ( - - - - {label} - + ) : null} - ); - }} - + + + ); } @@ -1317,21 +765,6 @@ const SplitPaneView = memo(function SplitPaneView({ ); }); -function collectPanesById(node: SplitNode): Map { - const next = new Map(); - function visit(current: SplitNode) { - if (current.kind === "pane") { - next.set(current.pane.id, current.pane); - return; - } - for (const child of current.group.children) { - visit(child); - } - } - visit(node); - return next; -} - function getNodeKey(node: SplitNode): string { if (node.kind === "pane") { return node.pane.id; @@ -1396,12 +829,6 @@ const styles = StyleSheet.create((theme) => ({ minWidth: 0, minHeight: 0, }, - explorerSidebarDock: { - flexShrink: 0, - minWidth: 240, - minHeight: 0, - backgroundColor: theme.colors.surfaceSidebar, - }, group: { flex: 1, minWidth: 0, @@ -1436,18 +863,4 @@ const styles = StyleSheet.create((theme) => ({ minWidth: 0, minHeight: 0, }, - dragOverlayChip: { - flexDirection: "row", - alignItems: "center", - gap: theme.spacing[2], - paddingHorizontal: theme.spacing[3], - paddingVertical: theme.spacing[1], - borderRadius: theme.borderRadius.md, - borderWidth: 1, - maxWidth: 200, - }, - dragOverlayLabel: { - fontSize: theme.fontSize.base, - flexShrink: 1, - }, })); diff --git a/packages/app/src/components/split-drop-zone.tsx b/packages/app/src/components/split-drop-zone.tsx index b761f6b937..266c766cec 100644 --- a/packages/app/src/components/split-drop-zone.tsx +++ b/packages/app/src/components/split-drop-zone.tsx @@ -147,7 +147,7 @@ function getPreviewFrameStyle(position: SplitDropZonePosition) { const styles = StyleSheet.create((theme) => ({ overlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, zIndex: 40, }, previewOverlay: { diff --git a/packages/app/src/components/terminal-pane.tsx b/packages/app/src/components/terminal-pane.tsx index 31c36b607c..4b37470b30 100644 --- a/packages/app/src/components/terminal-pane.tsx +++ b/packages/app/src/components/terminal-pane.tsx @@ -1171,7 +1171,7 @@ const styles = StyleSheet.create((theme) => ({ minHeight: 0, }, attachOverlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, alignItems: "center", justifyContent: "center", backgroundColor: "rgba(0, 0, 0, 0.16)", diff --git a/packages/app/src/components/ui/combobox.tsx b/packages/app/src/components/ui/combobox.tsx index caf73d1bbc..7401f7aac3 100644 --- a/packages/app/src/components/ui/combobox.tsx +++ b/packages/app/src/components/ui/combobox.tsx @@ -1765,7 +1765,7 @@ const styles = StyleSheet.create((theme) => ({ flex: 1, }, desktopOverlayWeb: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, pointerEvents: "auto" as const, }, desktopBackdrop: { diff --git a/packages/app/src/components/ui/floating-panel-portal.tsx b/packages/app/src/components/ui/floating-panel-portal.tsx index c9c36375f4..21ea94a03f 100644 --- a/packages/app/src/components/ui/floating-panel-portal.tsx +++ b/packages/app/src/components/ui/floating-panel-portal.tsx @@ -81,6 +81,6 @@ export function FloatingPanelPortalHost({ const styles = StyleSheet.create({ host: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, }, }); diff --git a/packages/app/src/components/ui/hover-card.tsx b/packages/app/src/components/ui/hover-card.tsx index 3d438505d3..fd81294f80 100644 --- a/packages/app/src/components/ui/hover-card.tsx +++ b/packages/app/src/components/ui/hover-card.tsx @@ -14,13 +14,16 @@ import { Dimensions, View, type Role, type StyleProp, type ViewStyle } from "rea import { FadeIn, FadeOut } from "react-native-reanimated"; import { StyleSheet } from "react-native-unistyles"; import { Portal } from "@gorhom/portal"; -import { useBottomSheetModalInternal } from "@gorhom/bottom-sheet"; import { OverlayLayerProvider, useOverlayLayer, useWebOverlayRegistration, } from "@/lib/overlay-root"; import { FloatingSurface } from "@/components/ui/floating"; +import { + measureFloatingPanelPortalHost, + useFloatingPanelPortalHostName, +} from "@/components/ui/floating-panel-portal"; import { isWeb } from "@/constants/platform"; import { useHoverSafeZone } from "@/hooks/use-hover-safe-zone"; import { @@ -326,28 +329,31 @@ function HoverCardSurface({ triggerRef: RefObject; contentRef: RefObject; }): ReactElement { - const bottomSheetInternal = useBottomSheetModalInternal(true); - const [triggerRect, setTriggerRect] = useState(null); + const portalHostName = useFloatingPanelPortalHostName(); + const [anchor, setAnchor] = useState<{ triggerRect: Rect; hostRect: Rect } | null>(null); const [contentSize, setContentSize] = useState(null); const [position, setPosition] = useState<{ x: number; y: number } | null>(null); useEffect(() => { if (!triggerRef.current) return; let cancelled = false; - void measureElement(triggerRef.current).then((rect) => { - if (!cancelled) setTriggerRect(rect); + void Promise.all([ + measureElement(triggerRef.current), + measureFloatingPanelPortalHost(portalHostName), + ]).then(([triggerRect, hostRect]) => { + if (!cancelled && hostRect) setAnchor({ triggerRect, hostRect }); return undefined; }); return () => { cancelled = true; }; - }, [triggerRef]); + }, [portalHostName, triggerRef]); useEffect(() => { - if (!triggerRect || !contentSize) return; + if (!anchor || !contentSize) return; const { width, height } = Dimensions.get("window"); const { x, y } = computePosition({ - triggerRect, + triggerRect: anchor.triggerRect, contentSize, displayArea: { x: 0, y: 0, width, height }, placement, @@ -355,8 +361,8 @@ function HoverCardSurface({ alignment, offset, }); - setPosition({ x, y }); - }, [alignment, contentSize, offset, placement, triggerRect]); + setPosition({ x: x - anchor.hostRect.x, y: y - anchor.hostRect.y }); + }, [alignment, anchor, contentSize, offset, placement]); const handleLayout = useCallback( (event: { nativeEvent: { layout: { width: number; height: number } } }) => { @@ -377,7 +383,7 @@ function HoverCardSurface({ const surfaceStyle = useMemo(() => [styles.surface, style], [style]); return ( - + ({ flex: 1, }, overlayWeb: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, pointerEvents: "auto" as const, }, backdrop: { diff --git a/packages/app/src/components/ui/press-highlight.native.tsx b/packages/app/src/components/ui/press-highlight.native.tsx index 858e68843f..e1802dd689 100644 --- a/packages/app/src/components/ui/press-highlight.native.tsx +++ b/packages/app/src/components/ui/press-highlight.native.tsx @@ -66,9 +66,9 @@ export const PressHighlight = forwardRef(function Pre const styles = StyleSheet.create({ highlight: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, }, highlightFill: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, }, }); diff --git a/packages/app/src/components/ui/shortcut.tsx b/packages/app/src/components/ui/shortcut.tsx index d53788cb00..6be0cf353e 100644 --- a/packages/app/src/components/ui/shortcut.tsx +++ b/packages/app/src/components/ui/shortcut.tsx @@ -68,7 +68,7 @@ const styles = StyleSheet.create((theme) => ({ borderWidth: 0, }, badgeBackground: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.surface3, opacity: theme.opacity[50], diff --git a/packages/app/src/components/workspace-tab-drag-context.ts b/packages/app/src/components/workspace-tab-drag-context.ts new file mode 100644 index 0000000000..543997af13 --- /dev/null +++ b/packages/app/src/components/workspace-tab-drag-context.ts @@ -0,0 +1,12 @@ +import { createContext, useContext } from "react"; +import type { TabDropPreview } from "./split-container-tab-drop-preview"; +import type { SplitDropZoneHover } from "./split-drop-zone"; +export const WorkspaceTabDragContext = createContext<{ + activeDragTabId: string | null; + dropPreview: SplitDropZoneHover | null; + tabDropPreview: TabDropPreview | null; + externalDndContext: boolean; +}>({ activeDragTabId: null, dropPreview: null, tabDropPreview: null, externalDndContext: false }); +export function useWorkspaceTabDrag() { + return useContext(WorkspaceTabDragContext); +} diff --git a/packages/app/src/components/workspace-tab-drag-policy.ts b/packages/app/src/components/workspace-tab-drag-policy.ts new file mode 100644 index 0000000000..e2ac7a2dee --- /dev/null +++ b/packages/app/src/components/workspace-tab-drag-policy.ts @@ -0,0 +1,9 @@ +export function acceptsWorkspaceTabDrop( + allowCrossPane: boolean, + sourcePaneId: string, + destination: { kind: "workspace-tab" | "split-pane-drop"; paneId: string }, +): boolean { + return ( + allowCrossPane || (destination.kind === "workspace-tab" && sourcePaneId === destination.paneId) + ); +} diff --git a/packages/app/src/components/workspace-tab-drag-scope.tsx b/packages/app/src/components/workspace-tab-drag-scope.tsx new file mode 100644 index 0000000000..4c3f077632 --- /dev/null +++ b/packages/app/src/components/workspace-tab-drag-scope.tsx @@ -0,0 +1,5 @@ +import type { ComponentProps } from "react"; +import type { WorkspaceTabDragScope as WebScope } from "./workspace-tab-drag-scope.web"; +export function WorkspaceTabDragScope({ children }: ComponentProps) { + return children; +} diff --git a/packages/app/src/components/workspace-tab-drag-scope.web.tsx b/packages/app/src/components/workspace-tab-drag-scope.web.tsx new file mode 100644 index 0000000000..3ff9bc3b10 --- /dev/null +++ b/packages/app/src/components/workspace-tab-drag-scope.web.tsx @@ -0,0 +1,494 @@ +import { useCallback, useMemo, useState, type ReactNode } from "react"; +import { View, Text } from "react-native"; +import { useTranslation } from "react-i18next"; +import { StyleSheet } from "react-native-unistyles"; +import { + DndContext, + DragOverlay, + KeyboardSensor, + PointerSensor, + closestCenter, + pointerWithin, + useSensor, + useSensors, + type CollisionDetection, + type DragEndEvent, + type DragMoveEvent, + type DragOverEvent, + type DragStartEvent, +} from "@dnd-kit/core"; +import { arrayMove, sortableKeyboardCoordinates } from "@dnd-kit/sortable"; +import { computeTabDropPreview, type TabDropPreview } from "./split-container-tab-drop-preview"; +import { resolveSplitDropPosition, type SplitDropZoneHover } from "./split-drop-zone"; +import { getWorkspacePaneDescriptors } from "@/screens/workspace/workspace-pane-state"; +import { + WorkspaceTabPresentationResolver, + WorkspaceTabIcon, +} from "@/screens/workspace/workspace-tab-presentation"; +import type { WorkspaceTabDescriptor } from "@/screens/workspace/workspace-tabs-types"; +import { + collectAllPanes, + createWorkspaceLayoutWithExplorerSidebar, + type WorkspaceLayout, + type SplitPane, +} from "@/stores/workspace-layout-store"; +import type { WorkspaceTab } from "@/workspace-tabs/model"; +import { panelTargetSupportsHost } from "@/plugins/workspace-panels/locations"; +import { acceptsWorkspaceTabDrop } from "./workspace-tab-drag-policy"; +import { WorkspaceTabDragContext } from "./workspace-tab-drag-context"; +interface WorkspaceTabDragData { + kind: "workspace-tab"; + paneId: string; + tabId: string; +} + +interface SplitPaneDropData { + kind: "split-pane-drop"; + paneId: string; +} + +function isWorkspaceTabDragData(data: unknown): data is WorkspaceTabDragData { + return typeof data === "object" && data !== null && Reflect.get(data, "kind") === "workspace-tab"; +} + +function isSplitPaneDropData(data: unknown): data is SplitPaneDropData { + return ( + typeof data === "object" && data !== null && Reflect.get(data, "kind") === "split-pane-drop" + ); +} + +function asWorkspaceTabDragData(data: unknown): WorkspaceTabDragData | undefined { + return isWorkspaceTabDragData(data) ? data : undefined; +} + +function asDragOverData(data: unknown): WorkspaceTabDragData | SplitPaneDropData | undefined { + if (isWorkspaceTabDragData(data)) return data; + if (isSplitPaneDropData(data)) return data; + return undefined; +} + +interface DragMoveRects { + translatedRect: { left: number; top: number; width: number; height: number }; + overRect: { left: number; top: number; width: number; height: number }; +} + +function resolveDragMoveRects( + event: Pick | Pick, +): DragMoveRects | null { + const translatedRect = event.active.rect.current.translated; + const overRect = event.over?.rect; + if (!translatedRect || !overRect || overRect.width <= 0 || overRect.height <= 0) { + return null; + } + return { translatedRect, overRect }; +} + +function computeTabOverDropPreview(input: { + activeData: WorkspaceTabDragData; + overData: WorkspaceTabDragData; + rects: DragMoveRects; + panesById: Map; + uiTabs: WorkspaceTab[]; +}): TabDropPreview | null { + const { activeData, overData, rects, panesById, uiTabs } = input; + const targetPane = panesById.get(overData.paneId) ?? null; + if (!targetPane) { + return null; + } + const targetTabs = getWorkspacePaneDescriptors({ pane: targetPane, tabs: uiTabs }); + return computeTabDropPreview({ + activePaneId: activeData.paneId, + activeTabId: activeData.tabId, + overPaneId: overData.paneId, + overTabId: overData.tabId, + targetTabs, + activeRect: { + left: rects.translatedRect.left, + width: rects.translatedRect.width, + }, + overRect: { + left: rects.overRect.left, + width: rects.overRect.width, + }, + }); +} + +function computePaneOverDropPreview(input: { + overData: SplitPaneDropData; + rects: DragMoveRects; +}): SplitDropZoneHover | null { + const { overData, rects } = input; + const centerX = rects.translatedRect.left + rects.translatedRect.width / 2; + const centerY = rects.translatedRect.top + rects.translatedRect.height / 2; + const relativeX = centerX - rects.overRect.left; + const relativeY = centerY - rects.overRect.top; + if ( + Number.isNaN(relativeX) || + Number.isNaN(relativeY) || + relativeX < 0 || + relativeX > rects.overRect.width || + relativeY < 0 || + relativeY > rects.overRect.height + ) { + return null; + } + return { + paneId: overData.paneId, + position: resolveSplitDropPosition({ + width: rects.overRect.width, + height: rects.overRect.height, + x: relativeX, + y: relativeY, + }), + }; +} + +const dropCollisionDetection: CollisionDetection = (args) => { + const pointerHits = pointerWithin(args); + const tabHits = pointerHits.filter( + (entry) => entry.data?.droppableContainer.data.current?.kind === "workspace-tab", + ); + if (tabHits.length > 0) { + return tabHits; + } + + const paneHits = pointerHits.filter( + (entry) => entry.data?.droppableContainer.data.current?.kind === "split-pane-drop", + ); + if (paneHits.length > 0) { + return paneHits; + } + + return closestCenter(args); +}; + +const EMPTY_LAYOUT = createWorkspaceLayoutWithExplorerSidebar(); + +interface WorkspaceTabDragScopeProps { + children: ReactNode; + layout: WorkspaceLayout | null; + explorerSidebarPaneId: string | null; + allowCrossPane: boolean; + normalizedServerId: string; + normalizedWorkspaceId: string; + uiTabs: WorkspaceTab[]; + onMoveTabToPane: (tabId: string, paneId: string) => void; + onReorderTabsInPane: (paneId: string, tabIds: string[]) => void; + onSplitPane: (input: { + tabId: string; + targetPaneId: string; + position: "left" | "right" | "top" | "bottom"; + }) => void; +} +export function WorkspaceTabDragScope({ + children, + layout, + explorerSidebarPaneId, + allowCrossPane, + normalizedServerId, + normalizedWorkspaceId, + uiTabs, + onMoveTabToPane, + onReorderTabsInPane, + onSplitPane, +}: WorkspaceTabDragScopeProps) { + const [activeDragTabId, setActiveDragTabId] = useState(null); + const [dropPreview, setDropPreview] = useState(null); + const [tabDropPreview, setTabDropPreview] = useState(null); + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { + distance: 8, + }, + }), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }), + ); + + const panesById = useMemo( + () => new Map(collectAllPanes((layout ?? EMPTY_LAYOUT).root).map((pane) => [pane.id, pane])), + [layout], + ); + const handleDragStart = useCallback((event: DragStartEvent) => { + const data = asWorkspaceTabDragData(event.active.data.current); + if (!data) { + setActiveDragTabId(null); + setDropPreview(null); + setTabDropPreview(null); + return; + } + setActiveDragTabId(data.tabId); + }, []); + + const handleDragCancel = useCallback(() => { + setActiveDragTabId(null); + setDropPreview(null); + setTabDropPreview(null); + }, []); + + const updateDropPreview = useCallback( + (event: Pick | Pick) => { + const activeData = asWorkspaceTabDragData(event.active.data.current); + const overData = asDragOverData(event.over?.data.current); + + if ( + !activeData || + !overData || + !acceptsWorkspaceTabDrop(allowCrossPane, activeData.paneId, overData) + ) { + setDropPreview(null); + setTabDropPreview(null); + return; + } + + const rects = resolveDragMoveRects(event); + if (!rects) { + setDropPreview(null); + setTabDropPreview(null); + return; + } + + const activeTab = uiTabs.find((tab) => tab.tabId === activeData.tabId) ?? null; + const destinationPaneId = + overData?.kind === "workspace-tab" || overData?.kind === "split-pane-drop" + ? overData.paneId + : null; + const destinationHost = destinationPaneId === explorerSidebarPaneId ? "explorer" : "main"; + if ( + !activeTab || + !panelTargetSupportsHost(normalizedServerId, activeTab.target, destinationHost) + ) { + setDropPreview(null); + setTabDropPreview(null); + return; + } + + if (overData?.kind === "workspace-tab") { + const preview = computeTabOverDropPreview({ + activeData, + overData, + rects, + panesById, + uiTabs, + }); + setDropPreview(null); + setTabDropPreview(preview); + return; + } + + setTabDropPreview(null); + if (overData?.kind !== "split-pane-drop") { + setDropPreview(null); + return; + } + + setDropPreview(computePaneOverDropPreview({ overData, rects })); + }, + [allowCrossPane, normalizedServerId, panesById, explorerSidebarPaneId, uiTabs], + ); + + const applyTabDropEnd = useCallback( + (input: { activeData: WorkspaceTabDragData; overData: WorkspaceTabDragData }): void => { + const { activeData, overData } = input; + const sourcePane = panesById.get(activeData.paneId) ?? null; + const targetPane = panesById.get(overData.paneId) ?? null; + if (!sourcePane || !targetPane) { + return; + } + + const sourceTabs = getWorkspacePaneDescriptors({ pane: sourcePane, tabs: uiTabs }); + const targetTabs = getWorkspacePaneDescriptors({ pane: targetPane, tabs: uiTabs }); + const sourceIndex = sourceTabs.findIndex((tab) => tab.tabId === activeData.tabId); + const resolvedTabDropPreview = + tabDropPreview?.paneId === overData.paneId ? tabDropPreview : null; + if (sourceIndex < 0 || !resolvedTabDropPreview) { + return; + } + + if (activeData.paneId === overData.paneId) { + if (sourceIndex !== resolvedTabDropPreview.insertionIndex) { + const nextTabs = arrayMove( + sourceTabs, + sourceIndex, + resolvedTabDropPreview.insertionIndex, + ); + onReorderTabsInPane( + activeData.paneId, + nextTabs.map((tab) => tab.tabId), + ); + } + return; + } + + const nextTargetTabIds = targetTabs.map((tab) => tab.tabId); + nextTargetTabIds.splice(resolvedTabDropPreview.insertionIndex, 0, activeData.tabId); + onMoveTabToPane(activeData.tabId, overData.paneId); + onReorderTabsInPane(overData.paneId, nextTargetTabIds); + }, + [onMoveTabToPane, onReorderTabsInPane, panesById, tabDropPreview, uiTabs], + ); + + const applyPaneDropEnd = useCallback( + (input: { activeData: WorkspaceTabDragData; overData: SplitPaneDropData }): void => { + const { activeData, overData } = input; + if (dropPreview?.paneId !== overData.paneId) { + return; + } + if (dropPreview.position === "center") { + if (activeData.paneId !== overData.paneId) { + onMoveTabToPane(activeData.tabId, overData.paneId); + } + return; + } + onSplitPane({ + tabId: activeData.tabId, + targetPaneId: overData.paneId, + position: dropPreview.position, + }); + }, + [dropPreview, onMoveTabToPane, onSplitPane], + ); + + const handleDragEnd = useCallback( + (event: DragEndEvent) => { + const activeData = asWorkspaceTabDragData(event.active.data.current); + const overData = asDragOverData(event.over?.data.current); + + setActiveDragTabId(null); + + if ( + activeData && + overData && + event.over && + acceptsWorkspaceTabDrop(allowCrossPane, activeData.paneId, overData) + ) { + if (overData?.kind === "workspace-tab") { + applyTabDropEnd({ activeData, overData }); + } else if (overData?.kind === "split-pane-drop") { + applyPaneDropEnd({ activeData, overData }); + } + } + + setDropPreview(null); + setTabDropPreview(null); + }, + [allowCrossPane, applyTabDropEnd, applyPaneDropEnd], + ); + + const context = useMemo( + () => ({ activeDragTabId, dropPreview, tabDropPreview, externalDndContext: true }), + [activeDragTabId, dropPreview, tabDropPreview], + ); + return ( + + {children} + + {activeDragTabId ? ( + + ) : null} + + + ); +} +function DragOverlayTabChip({ + tabId, + uiTabs, + normalizedServerId, + normalizedWorkspaceId, +}: { + tabId: string; + uiTabs: WorkspaceTab[]; + normalizedServerId: string; + normalizedWorkspaceId: string; +}) { + const tab = uiTabs.find((t) => t.tabId === tabId); + const descriptor = useMemo( + () => + tab + ? { + key: tab.tabId, + tabId: tab.tabId, + kind: tab.target.kind, + target: tab.target, + } + : null, + [tab], + ); + if (!descriptor) { + return null; + } + return ( + + ); +} + +function DragOverlayTabChipInner({ + tab, + normalizedServerId, + normalizedWorkspaceId, +}: { + tab: WorkspaceTabDescriptor; + normalizedServerId: string; + normalizedWorkspaceId: string; +}) { + const { t } = useTranslation(); + return ( + + {(presentation) => { + const label = + presentation.titleState === "loading" ? t("common.states.loading") : presentation.label; + + return ( + + + + {label} + + + ); + }} + + ); +} + +const styles = StyleSheet.create((theme) => ({ + dragOverlayChip: { + backgroundColor: theme.colors.surface1, + borderColor: theme.colors.borderAccent, + flexDirection: "row", + alignItems: "center", + gap: theme.spacing[2], + paddingHorizontal: theme.spacing[3], + paddingVertical: theme.spacing[1], + borderRadius: theme.borderRadius.md, + borderWidth: 1, + maxWidth: 200, + }, + dragOverlayLabel: { + color: theme.colors.foreground, + fontSize: theme.fontSize.base, + flexShrink: 1, + }, +})); diff --git a/packages/app/src/composer/draft/workspace-tab.tsx b/packages/app/src/composer/draft/workspace-tab.tsx index 27ca8b8af8..d00b6f7790 100644 --- a/packages/app/src/composer/draft/workspace-tab.tsx +++ b/packages/app/src/composer/draft/workspace-tab.tsx @@ -415,11 +415,10 @@ export function WorkspaceDraftAgentTab({ openWorkspaceChanges({ isCompact: isCompactFormFactor, workspaceKey: buildWorkspaceTabPersistenceKey({ serverId, workspaceId: workspaceId ?? "" }), - checkout: { serverId, cwd: composerState.workingDir, isGit: true }, preferences: openInSidePane, }); }, - [composerState.workingDir, isCompactFormFactor, openInSidePane, serverId, workspaceId], + [isCompactFormFactor, openInSidePane, serverId, workspaceId], ); const { diff --git a/packages/app/src/constants/layout.ts b/packages/app/src/constants/layout.ts index 9e9a15f6b4..96aee0e828 100644 --- a/packages/app/src/constants/layout.ts +++ b/packages/app/src/constants/layout.ts @@ -33,7 +33,7 @@ export { getIsElectronMac as getIsElectronRuntimeMac, } from "./platform"; -/** Compact layouts are the breakpoints below `md`. */ +/** Below 600 points, sidebars overlay the workspace. Medium and wider layouts dock them. */ export function isCompactBreakpoint(breakpoint: string | undefined): boolean { return breakpoint === "xs" || breakpoint === "sm"; } diff --git a/packages/app/src/desktop/components/integrations-section.tsx b/packages/app/src/desktop/components/integrations-section.tsx index 609aa9add4..b5422b71bc 100644 --- a/packages/app/src/desktop/components/integrations-section.tsx +++ b/packages/app/src/desktop/components/integrations-section.tsx @@ -1,7 +1,7 @@ import { useCallback, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { Text, View } from "react-native"; -import { useFocusEffect } from "@react-navigation/native"; +import { useFocusEffect } from "expo-router/react-navigation"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { ArrowUpRight, Check, Terminal } from "lucide-react-native"; import { Button } from "@/components/ui/button"; diff --git a/packages/app/src/file-pane/pane.tsx b/packages/app/src/file-pane/pane.tsx index 8e43931677..04707d561b 100644 --- a/packages/app/src/file-pane/pane.tsx +++ b/packages/app/src/file-pane/pane.tsx @@ -3,7 +3,7 @@ import { LoadingSpinner } from "@/components/ui/loading-spinner"; import React, { useCallback, useEffect, useMemo, useState, useSyncExternalStore } from "react"; import type { DaemonClient } from "@getpaseo/client/internal/daemon-client"; import { Text, View } from "react-native"; -import { StyleSheet, UnistylesRuntime, withUnistyles } from "react-native-unistyles"; +import { StyleSheet, withUnistyles } from "react-native-unistyles"; import { useTranslation } from "react-i18next"; import { useIsCompactFormFactor } from "@/constants/layout"; import { useSessionStore, type ExplorerFile } from "@/stores/session-store"; @@ -31,6 +31,25 @@ import { confirmDialog } from "@/utils/confirm-dialog"; import { usePublishPanelInstanceAttributes } from "@/panels/panel-instance-attributes"; import type { Theme } from "@/styles/theme"; +// CodeMirror and native source rendering consume appearance as props. Subscribe at the +// rendering leaf so theme updates reconfigure it without replacing the editor/model. +const sourceAppearance = (theme: Theme) => ({ + theme: { + colorScheme: theme.colorScheme, + background: theme.colors.surface0, + foreground: theme.colors.foreground, + cursor: theme.colors.terminal.cursor, + foregroundMuted: theme.colors.foregroundMuted, + border: theme.colors.border, + selection: theme.colors.terminal.selectionBackground, + monoFont: theme.fontFamily.mono, + codeFontSize: theme.fontSize.code, + syntax: theme.colors.syntax, + }, +}); +const ThemedFileEditorView = withUnistyles(FileEditorView, sourceAppearance); +const ThemedFileSourceView = withUnistyles(FileSourceView, sourceAppearance); + const ThemedLoadingSpinner = withUnistyles(LoadingSpinner); const foregroundMutedColorMapping = (theme: Theme) => ({ color: theme.colors.foregroundMuted, @@ -81,31 +100,14 @@ function ReadonlySource({ location: WorkspaceFileLocation; navigationRevision: number; }) { - const theme = UnistylesRuntime.getTheme(); const { t } = useTranslation(); - const visualTheme = useMemo( - () => ({ - colorScheme: theme.colorScheme, - background: theme.colors.surface0, - foreground: theme.colors.foreground, - cursor: theme.colors.terminal.cursor, - foregroundMuted: theme.colors.foregroundMuted, - border: theme.colors.border, - selection: theme.colors.terminal.selectionBackground, - monoFont: theme.fontFamily.mono, - codeFontSize: theme.fontSize.code, - syntax: theme.colors.syntax, - }), - [theme], - ); return ( - ); @@ -511,34 +513,6 @@ function EditableFilePane({ const snapshot = useSyncExternalStore(model.subscribe, model.getSnapshot, model.getSnapshot); const suspendPendingSave = useCallback(() => model.suspendAutosave(), [model]); usePublishPanelInstanceAttributes({ modified: snapshot.modified, suspendPendingSave }); - const theme = UnistylesRuntime.getTheme(); - const visualTheme = useMemo( - () => ({ - colorScheme: theme.colorScheme, - background: theme.colors.surface0, - foreground: theme.colors.foreground, - cursor: theme.colors.terminal.cursor, - foregroundMuted: theme.colors.foregroundMuted, - border: theme.colors.border, - selection: theme.colors.terminal.selectionBackground, - monoFont: theme.fontFamily.mono, - codeFontSize: theme.fontSize.code, - syntax: theme.colors.syntax, - }), - [ - theme.colors.border, - theme.colors.foreground, - theme.colors.foregroundMuted, - theme.colors.surface0, - theme.colors.syntax, - theme.colors.terminal.cursor, - theme.colors.terminal.selectionBackground, - theme.colorScheme, - theme.fontFamily.mono, - theme.fontSize.code, - ], - ); - useEffect(() => () => model.dispose(), [model]); const handleReload = useCallback(() => { @@ -592,13 +566,12 @@ function EditableFilePane({ onModeChange={onModeChange} /> {showSource ? ( - diff --git a/packages/app/src/git/diff-pane.tsx b/packages/app/src/git/diff-pane.tsx index 6bafd3eee3..22a5c2df05 100644 --- a/packages/app/src/git/diff-pane.tsx +++ b/packages/app/src/git/diff-pane.tsx @@ -1427,10 +1427,9 @@ function useDiffTabNavigation({ openWorkspacePullRequest({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: { serverId, cwd, isGit: true }, destination: pullRequestOpenLocation, }); - }, [cwd, isMobile, persistenceKey, pullRequestOpenLocation, serverId]); + }, [isMobile, persistenceKey, pullRequestOpenLocation]); return { openDiff, openCommit, diff --git a/packages/app/src/git/pull-request-connection.tsx b/packages/app/src/git/pull-request-connection.tsx new file mode 100644 index 0000000000..1f407cb006 --- /dev/null +++ b/packages/app/src/git/pull-request-connection.tsx @@ -0,0 +1,27 @@ +import { createContext, useContext, type ReactNode } from "react"; +import type { DaemonClient } from "@getpaseo/client/internal/daemon-client"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; + +export interface PullRequestConnection { + client: Pick | null; + isConnected: boolean; +} +const ConnectionContext = createContext<((serverId: string) => PullRequestConnection) | null>(null); + +/** Supplies the PR read connection, shared by discovery, rail status and timeline content. */ +export function PullRequestConnectionProvider({ + connection, + children, +}: { + connection: (serverId: string) => PullRequestConnection; + children: ReactNode; +}) { + return {children}; +} + +export function usePullRequestConnection(serverId: string): PullRequestConnection { + const supplied = useContext(ConnectionContext); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); + return supplied ? supplied(serverId) : { client, isConnected }; +} diff --git a/packages/app/src/git/pull-request-panel/use-data.test.ts b/packages/app/src/git/pull-request-panel/use-data.test.ts index 0e8a7edd97..e40b2889b5 100644 --- a/packages/app/src/git/pull-request-panel/use-data.test.ts +++ b/packages/app/src/git/pull-request-panel/use-data.test.ts @@ -406,7 +406,7 @@ describe("selectPrPaneState", () => { expect(state.data?.forgeSpecific).toEqual({ ...gitlabFacts, mergeStatus: null }); }); - it("returns null data when the consumer disabled timeline rendering", () => { + it("keeps cached content when retained activity disables timeline demand", () => { const state = selectPrPaneState({ ...baseSelectInput, status: prStatus(), @@ -414,7 +414,7 @@ describe("selectPrPaneState", () => { timelinePayload: timelinePayload(), }); - expect(state.data).toBeNull(); + expect(state.data).not.toBeNull(); expect(state.prNumber).toBe(42); }); diff --git a/packages/app/src/git/pull-request-panel/use-data.ts b/packages/app/src/git/pull-request-panel/use-data.ts index f43394cf7e..d3e8beb3ec 100644 --- a/packages/app/src/git/pull-request-panel/use-data.ts +++ b/packages/app/src/git/pull-request-panel/use-data.ts @@ -1,7 +1,7 @@ import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; -import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; +import { usePullRequestConnection } from "@/git/pull-request-connection"; import type { CheckoutPrStatusResponse, PullRequestTimelineResponse, @@ -20,7 +20,7 @@ type PullRequestTimeline = PullRequestTimelineResponse["payload"]; export interface UsePrPaneDataOptions { serverId: string; cwd: string; - enabled?: boolean; + enabled: boolean; timelineEnabled?: boolean; } @@ -166,7 +166,7 @@ export interface SelectPrPaneStateInput { export function selectPrPaneState(input: SelectPrPaneStateInput): UsePrPaneDataResult { const identity = extractPrRepoIdentity(input.status); const data = - identity.prNumber === null || !input.timelineEnabled + identity.prNumber === null ? null : mapPrPaneData(input.status, input.timelinePayload, undefined, input.forge ?? "github"); const statusRefreshing = input.statusIsFetching && !input.statusIsLoading; @@ -198,12 +198,11 @@ export function selectPrPaneState(input: SelectPrPaneStateInput): UsePrPaneDataR export function usePrPaneData({ serverId, cwd, - enabled = true, + enabled, timelineEnabled = enabled, }: UsePrPaneDataOptions): UsePrPaneDataResult { const { t } = useTranslation(); - const daemonClient = useHostRuntimeClient(serverId); - const isConnected = useHostRuntimeIsConnected(serverId); + const { client: daemonClient, isConnected } = usePullRequestConnection(serverId); const checkoutPrStatus = useCheckoutPrStatusQuery({ serverId, cwd, enabled }); const status = checkoutPrStatus.status; const identity = extractPrRepoIdentity(status); diff --git a/packages/app/src/git/use-pr-status-query.ts b/packages/app/src/git/use-pr-status-query.ts index e8e4bf2b14..bd36543977 100644 --- a/packages/app/src/git/use-pr-status-query.ts +++ b/packages/app/src/git/use-pr-status-query.ts @@ -1,6 +1,6 @@ import { useQuery } from "@tanstack/react-query"; import { useTranslation } from "react-i18next"; -import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; +import { usePullRequestConnection } from "@/git/pull-request-connection"; import { checkoutPrStatusQueryKey } from "@/git/query-keys"; import { normalizeForge } from "@/git/forge"; import { selectPrHintFromStatus, type PrHint } from "@/git/pr-hint"; @@ -25,8 +25,7 @@ export function useCheckoutPrStatusQuery({ enabled = true, }: UseCheckoutPrStatusQueryOptions) { const { t } = useTranslation(); - const client = useHostRuntimeClient(serverId); - const isConnected = useHostRuntimeIsConnected(serverId); + const { client, isConnected } = usePullRequestConnection(serverId); const query = useQuery({ queryKey: checkoutPrStatusQueryKey(serverId, cwd), @@ -67,8 +66,7 @@ export function useWorkspacePrHint({ enabled = true, }: UseCheckoutPrStatusQueryOptions): PrHint | null { const { t } = useTranslation(); - const client = useHostRuntimeClient(serverId); - const isConnected = useHostRuntimeIsConnected(serverId); + const { client, isConnected } = usePullRequestConnection(serverId); const query = useQuery({ queryKey: checkoutPrStatusQueryKey(serverId, cwd), diff --git a/packages/app/src/hosts/host-chooser.tsx b/packages/app/src/hosts/host-chooser.tsx index 5181fb65a4..c0b62697e0 100644 --- a/packages/app/src/hosts/host-chooser.tsx +++ b/packages/app/src/hosts/host-chooser.tsx @@ -292,7 +292,7 @@ const styles = StyleSheet.create((theme) => ({ paddingTop: theme.spacing[12], }, backdrop: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, backgroundColor: "rgba(0, 0, 0, 0.5)", }, panel: { diff --git a/packages/app/src/keyboard/shift/index.ts b/packages/app/src/keyboard/shift/index.ts index 3c56692919..5f057d4ecd 100644 --- a/packages/app/src/keyboard/shift/index.ts +++ b/packages/app/src/keyboard/shift/index.ts @@ -1,5 +1,4 @@ export { KeyboardShiftProvider, useKeyboardShiftStyle } from "./internal/provider"; export { useKeyboardShift, useSettledKeyboardShift } from "./internal/context"; export { KeyboardTranslateView } from "./internal/translate"; -export { shouldUseCompactExplorerKeyboardPadding } from "./internal/policy"; export { useKeyboardStreamInset } from "./internal/stream"; diff --git a/packages/app/src/keyboard/shift/internal/policy.test.ts b/packages/app/src/keyboard/shift/internal/policy.test.ts index 330cb2cfab..7c4902afe1 100644 --- a/packages/app/src/keyboard/shift/internal/policy.test.ts +++ b/packages/app/src/keyboard/shift/internal/policy.test.ts @@ -4,7 +4,6 @@ import { shouldReconcileHiddenKeyboardEnd, resolveKeyboardShift, reserveKeyboardLayoutShift, - shouldUseCompactExplorerKeyboardPadding, } from "./policy"; describe("keyboard layout reservation", () => { @@ -106,17 +105,3 @@ describe("shouldReconcileHiddenKeyboardEnd", () => { ).toBe(false); }); }); - -describe("shouldUseCompactExplorerKeyboardPadding", () => { - it("keeps the changes viewport stable while preserving padding for other tabs", () => { - expect(shouldUseCompactExplorerKeyboardPadding({ isGit: true, explorerTab: "changes" })).toBe( - false, - ); - expect(shouldUseCompactExplorerKeyboardPadding({ isGit: true, explorerTab: "files" })).toBe( - true, - ); - expect(shouldUseCompactExplorerKeyboardPadding({ isGit: false, explorerTab: "changes" })).toBe( - true, - ); - }); -}); diff --git a/packages/app/src/keyboard/shift/internal/policy.ts b/packages/app/src/keyboard/shift/internal/policy.ts index 97435027fa..fe496fd110 100644 --- a/packages/app/src/keyboard/shift/internal/policy.ts +++ b/packages/app/src/keyboard/shift/internal/policy.ts @@ -30,13 +30,6 @@ export function resolveStreamKeyboardInset(input: { }; } -export function shouldUseCompactExplorerKeyboardPadding(input: { - isGit: boolean; - explorerTab: "changes" | "files" | "pr"; -}): boolean { - return !input.isGit || input.explorerTab !== "changes"; -} - export function resolveKeyboardShift(input: { rawKeyboardHeight: number; keyboardProgress: number; diff --git a/packages/app/src/mobile-panels/explorer-open-gesture.tsx b/packages/app/src/mobile-panels/explorer-open-gesture.tsx new file mode 100644 index 0000000000..a71f0489cf --- /dev/null +++ b/packages/app/src/mobile-panels/explorer-open-gesture.tsx @@ -0,0 +1,60 @@ +import { type ReactNode, useCallback } from "react"; +import { View } from "react-native"; +import { GestureDetector } from "react-native-gesture-handler"; +import { useOpenFileExplorerGesture } from "@/mobile-panels/gestures"; +import { useActiveWorkspaceSelection } from "@/stores/navigation-active-workspace-store"; +import { useWorkspace } from "@/stores/session-store-hooks"; +import { showExplorerSidebar } from "@/workspace-tabs/explorer-sidebar"; +import { isWeb } from "@/constants/platform"; + +interface CompactExplorerOpenGestureSurfaceProps { + children: ReactNode; + enabled: boolean; + onOpenExplorer: () => void; +} + +const COMPACT_WEB_GESTURE_TOUCH_ACTION = isWeb ? "auto" : "pan-y"; + +function CompactExplorerOpenGestureSurface({ + children, + enabled, + onOpenExplorer, +}: CompactExplorerOpenGestureSurfaceProps) { + const explorerOpenGesture = useOpenFileExplorerGesture({ + enabled, + onOpen: onOpenExplorer, + }); + + return ( + + {children} + + ); +} + +export function WorkspaceExplorerOpenGesture({ + children, + enabled, +}: { + children: ReactNode; + enabled: boolean; +}) { + const selection = useActiveWorkspaceSelection(); + const workspace = useWorkspace(selection?.serverId ?? null, selection?.workspaceId ?? null); + const handleOpen = useCallback(() => { + if (!selection || !workspace) return; + showExplorerSidebar({ + isCompact: true, + workspaceKey: `${selection.serverId}:${selection.workspaceId}`, + }); + }, [selection, workspace]); + return ( + + {children} + + ); +} +const styles = { fill: { flex: 1 } }; diff --git a/packages/app/src/mobile-panels/gestures.ts b/packages/app/src/mobile-panels/gestures.ts index 84e5d48d09..2b3f3e11fe 100644 --- a/packages/app/src/mobile-panels/gestures.ts +++ b/packages/app/src/mobile-panels/gestures.ts @@ -1,5 +1,5 @@ -import { useCallback, useMemo } from "react"; -import { Gesture } from "react-native-gesture-handler"; +import { createContext, useContext, useRef, type RefObject, useCallback, useMemo } from "react"; +import { Gesture, type GestureType } from "react-native-gesture-handler"; import { useSharedValue } from "react-native-reanimated"; import { scheduleOnRN } from "react-native-worklets"; import { isWeb } from "@/constants/platform"; @@ -324,16 +324,14 @@ export function useOpenFileExplorerGesture({ enabled, onOpen }: OpenFileExplorer ); } -export function useCloseFileExplorerGesture() { - const { - beginGesture, - finishGesture, - motionState, - position, - rightCloseGestureRef, - updateGesture, - windowWidth, - } = useMobilePanelsRuntime(); +export const FileExplorerCloseGestureContext = createContext | null>(null); + +export function useCloseFileExplorerGesture(enabled = true) { + const rightCloseGestureRef = useRef(undefined); + const { beginGesture, finishGesture, motionState, position, updateGesture, windowWidth } = + useMobilePanelsRuntime(); const { startedRevision, touchStartX, touchStartY } = useGestureState(); const horizontalScroll = useHorizontalScrollOptional(); const showMobileAgent = usePanelStore((state) => state.showMobileAgent); @@ -343,6 +341,7 @@ export function useCloseFileExplorerGesture() { () => Gesture.Pan() .withRef(rightCloseGestureRef) + .enabled(enabled) .manualActivation(true) .onTouchesDown((event) => { const touch = event.changedTouches[0]; @@ -401,6 +400,7 @@ export function useCloseFileExplorerGesture() { } }), [ + enabled, beginGesture, commit, finishGesture, @@ -420,5 +420,5 @@ export function useCloseFileExplorerGesture() { } export function useFileExplorerCloseGestureRef() { - return useMobilePanelsRuntime().rightCloseGestureRef; + return useContext(FileExplorerCloseGestureContext); } diff --git a/packages/app/src/mobile-panels/presentation.tsx b/packages/app/src/mobile-panels/presentation.tsx index 77059dfc39..cb919e4595 100644 --- a/packages/app/src/mobile-panels/presentation.tsx +++ b/packages/app/src/mobile-panels/presentation.tsx @@ -1,5 +1,5 @@ -import { useMemo, type ComponentProps, type ReactNode } from "react"; -import { Pressable, StyleSheet, View } from "react-native"; +import { useId, useMemo, type ComponentProps, type ReactNode } from "react"; +import { Pressable, StyleSheet } from "react-native"; import { GestureDetector, type GestureType } from "react-native-gesture-handler"; import Animated, { useAnimatedStyle } from "react-native-reanimated"; import { isWeb } from "@/constants/platform"; @@ -14,6 +14,9 @@ interface MobilePanelOverlayProps { children: ReactNode; closeGesture: GestureType; panel: OverlayPanel; + presentation?: "overlay" | "dock"; + dockVisible?: boolean; + frameStyle?: ComponentProps["style"]; panelStyle?: ComponentProps["style"]; } @@ -22,18 +25,25 @@ export function MobilePanelOverlay({ closeGesture, panel, panelStyle, + presentation = "overlay", + dockVisible = false, + frameStyle, }: MobilePanelOverlayProps) { const { position, windowWidth } = useMobilePanelsRuntime(); const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const isOpen = useIsMobilePanelActive(panel); + const overlayOpen = useIsMobilePanelActive(panel); + const docked = presentation === "dock"; + const isOpen = docked ? dockVisible : overlayOpen; + const hostId = useId(); const isLeft = panel === "agent-list"; const sidebarAnimatedStyle = useAnimatedStyle(() => { + if (docked) return { transform: [{ translateX: 0 }] }; const frame = getMobilePanelFrame(position.value, windowWidth); return { transform: [{ translateX: isLeft ? frame.leftTranslateX : frame.rightTranslateX }], }; - }, [isLeft, windowWidth]); + }, [docked, isLeft, windowWidth]); const backdropAnimatedStyle = useAnimatedStyle(() => { const frame = getMobilePanelFrame(position.value, windowWidth); @@ -41,6 +51,7 @@ export function MobilePanelOverlay({ }, [isLeft, windowWidth]); const overlayAnimatedStyle = useAnimatedStyle(() => { + if (docked) return { opacity: 1, display: "flex" as const, pointerEvents: "box-none" as const }; const isVisible = isLeft ? position.value < 0 : position.value > 0; if (isWeb) { return { display: isVisible ? ("flex" as const) : ("none" as const) }; @@ -51,7 +62,7 @@ export function MobilePanelOverlay({ opacity: isVisible ? 1 : 0, pointerEvents: isVisible ? ("box-none" as const) : ("none" as const), }; - }, [isLeft]); + }, [docked, isLeft]); const positionedPanelStyle = isLeft ? styles.leftPanel : styles.rightPanel; const backdropStyle = useMemo( @@ -60,13 +71,13 @@ export function MobilePanelOverlay({ ); const combinedPanelStyle = useMemo( () => [ - styles.panel, - positionedPanelStyle, - { width: windowWidth }, + docked ? styles.dockedPanel : styles.panel, + !docked && positionedPanelStyle, + !docked && { width: windowWidth }, panelStyle, sidebarAnimatedStyle, ], - [panelStyle, positionedPanelStyle, sidebarAnimatedStyle, windowWidth], + [docked, panelStyle, positionedPanelStyle, sidebarAnimatedStyle, windowWidth], ); let overlayPointerEvents: "auto" | "box-none" | "none"; if (!isWeb) { @@ -79,22 +90,26 @@ export function MobilePanelOverlay({ {/* Fabric needs an always-mounted native host to attach the close handler while the retained panel content is hidden. nativeID keeps that host registered. */} - - + @@ -104,7 +119,7 @@ export function MobilePanelOverlay({ {children} - + ); } @@ -113,12 +128,14 @@ export function MobilePanelOverlay({ // Theme values stay inline at call sites, avoiding Unistyles patching the same // native node after Fabric commits. const styles = StyleSheet.create({ + dock: { flexShrink: 0, minHeight: 0 }, + dockedPanel: { flex: 1, minHeight: 0, overflow: "hidden" }, overlay: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, zIndex: 1, }, backdrop: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, backgroundColor: "rgba(0, 0, 0, 0.5)", }, panel: { diff --git a/packages/app/src/mobile-panels/provider.tsx b/packages/app/src/mobile-panels/provider.tsx index f88e3e6e74..b2f97a2547 100644 --- a/packages/app/src/mobile-panels/provider.tsx +++ b/packages/app/src/mobile-panels/provider.tsx @@ -49,7 +49,6 @@ interface MobilePanelsRuntime { motionState: SharedValue; openGesturesBlocked: SharedValue; position: SharedValue; - rightCloseGestureRef: RefObject; rightOpenGestureRef: RefObject; updateGesture: (startedRevision: number, nextPosition: number) => boolean; setOpenGestureBlocked: (owner: symbol, blocked: boolean) => void; @@ -79,7 +78,6 @@ export function MobilePanelsProvider({ children }: { children: ReactNode }) { const leftOpenGestureRef = useRef(undefined); const leftCloseGestureRef = useRef(undefined); const rightOpenGestureRef = useRef(undefined); - const rightCloseGestureRef = useRef(undefined); const [activePanel, setActivePanel] = useState(initialSelection.target); const setOpenGestureBlocked = useCallback( @@ -222,7 +220,6 @@ export function MobilePanelsProvider({ children }: { children: ReactNode }) { motionState, openGesturesBlocked, position, - rightCloseGestureRef, rightOpenGestureRef, updateGesture, setOpenGestureBlocked, diff --git a/packages/app/src/navigation/themed-stack.tsx b/packages/app/src/navigation/themed-stack.tsx index 010877c061..221cfc0ee4 100644 --- a/packages/app/src/navigation/themed-stack.tsx +++ b/packages/app/src/navigation/themed-stack.tsx @@ -1,9 +1,20 @@ -import type { NativeStackNavigationOptions } from "@react-navigation/native-stack"; import { Stack } from "expo-router"; -import { isValidElement, type ReactElement, type ReactNode, useCallback, useMemo } from "react"; +import { + isValidElement, + type ComponentProps, + type ReactElement, + type ReactNode, + useCallback, + useMemo, +} from "react"; import { withUnistyles } from "react-native-unistyles"; import { AppearanceStyleBoundary } from "@/components/appearance-style-boundary"; +type NativeStackNavigationOptions = Exclude< + NonNullable["screenOptions"]>, + (...args: never[]) => unknown +>; + interface ThemedStackBaseProps { backgroundColor: string; children?: ReactNode; @@ -11,6 +22,8 @@ interface ThemedStackBaseProps { // Screens whose content is another navigator. That navigator owns its own screens' appearance // boundary; wrapping it here would remount it. nestedNavigatorScreens?: readonly string[]; + /** Screens with retained lifetime owners update appearance at their own leaves. */ + screenOwnedAppearance?: readonly string[]; } interface ScreenContent { @@ -23,6 +36,7 @@ function ThemedStackBase({ children, screenOptions, nestedNavigatorScreens, + screenOwnedAppearance, }: ThemedStackBaseProps) { const themedScreenOptions = useMemo( () => ({ @@ -35,10 +49,15 @@ function ThemedStackBase({ // and its screen containers keep their identity. See docs/unistyles.md. const screenLayout = useCallback( ({ route, children: content }: ScreenContent): ReactElement => { - if (nestedNavigatorScreens?.includes(route.name) && isValidElement(content)) return content; + if ( + (nestedNavigatorScreens?.includes(route.name) || + screenOwnedAppearance?.includes(route.name)) && + isValidElement(content) + ) + return content; return {content}; }, - [nestedNavigatorScreens], + [nestedNavigatorScreens, screenOwnedAppearance], ); return ( diff --git a/packages/app/src/navigation/workspace-route-navigation.test.ts b/packages/app/src/navigation/workspace-route-navigation.test.ts index a331451ed5..841a31dc64 100644 --- a/packages/app/src/navigation/workspace-route-navigation.test.ts +++ b/packages/app/src/navigation/workspace-route-navigation.test.ts @@ -1,5 +1,5 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { NavigationContainerRefWithCurrent } from "@react-navigation/native"; +import type { NavigationContainerRefWithCurrent } from "expo-router/react-navigation"; import { navigateToHostWorkspaceRoute, registerWorkspaceRouteNavigationRef, diff --git a/packages/app/src/navigation/workspace-route-navigation.ts b/packages/app/src/navigation/workspace-route-navigation.ts index 06d0d23e07..d8b33ea305 100644 --- a/packages/app/src/navigation/workspace-route-navigation.ts +++ b/packages/app/src/navigation/workspace-route-navigation.ts @@ -2,7 +2,7 @@ import type { NavigationAction, NavigationContainerRef, NavigationContainerRefWithCurrent, -} from "@react-navigation/native"; +} from "expo-router/react-navigation"; import { router, type Href } from "expo-router"; import { encodeWorkspaceIdForPathSegment, diff --git a/packages/app/src/panels/agent-panel.tsx b/packages/app/src/panels/agent-panel.tsx index 7ae7d0c470..2fa2624fb4 100644 --- a/packages/app/src/panels/agent-panel.tsx +++ b/packages/app/src/panels/agent-panel.tsx @@ -1270,7 +1270,6 @@ const ChatAgentReadyContent = memo(function ChatAgentReadyContent({ serverId={serverId} workspaceId={workspaceId} agentId={agentId} - cwd={cwd} subagentRows={subagentRows} tasks={tasks} archiveFinishedStatus={archiveFinishedSubagents.status} @@ -1597,11 +1596,10 @@ function ActiveAgentComposer({ openWorkspaceChanges({ isCompact: isCompactFormFactor, workspaceKey: buildWorkspaceTabPersistenceKey({ serverId, workspaceId }), - checkout: { serverId, cwd, isGit: true }, preferences: openInSidePane, }); }, - [cwd, isCompactFormFactor, openInSidePane, serverId, workspaceId], + [isCompactFormFactor, openInSidePane, serverId, workspaceId], ); const handleClientSlashCommand = useCallback( diff --git a/packages/app/src/panels/agent-tracks.tsx b/packages/app/src/panels/agent-tracks.tsx index 86faad329c..e67a004b45 100644 --- a/packages/app/src/panels/agent-tracks.tsx +++ b/packages/app/src/panels/agent-tracks.tsx @@ -33,7 +33,6 @@ export const AgentTracks = memo(function AgentTracks({ serverId, workspaceId, agentId, - cwd, subagentRows, tasks, archiveFinishedStatus, @@ -43,7 +42,6 @@ export const AgentTracks = memo(function AgentTracks({ serverId: string; workspaceId: string; agentId: string; - cwd: string; subagentRows: SubagentRow[]; tasks: TodoEntry[] | undefined; archiveFinishedStatus: ArchiveFinishedStatus; @@ -99,10 +97,9 @@ export const AgentTracks = memo(function AgentTracks({ openComposerChanges({ isCompact, workspaceKey, - checkout: { serverId, cwd, isGit: true }, preferences: openInSidePane, }); - }, [cwd, isCompact, openInSidePane, serverId, workspaceKey]); + }, [isCompact, openInSidePane, workspaceKey]); if ( !hasWorkspaceDiffStat && diff --git a/packages/app/src/panels/changes/presentation.test.ts b/packages/app/src/panels/changes/presentation.test.ts new file mode 100644 index 0000000000..e0504376d8 --- /dev/null +++ b/packages/app/src/panels/changes/presentation.test.ts @@ -0,0 +1,22 @@ +import { expect, it } from "vitest"; +import { resolveChangesPresentation } from "./presentation"; + +it.each([ + [true, false, false, "combined"], + [true, false, true, "combined"], + [true, true, false, "combined"], + [false, true, false, "combined"], + [false, true, true, "combined"], + [false, false, false, "tree"], + [false, false, true, "combined"], +] as const)( + "Changes compact=%s native=%s inline=%s renders %s", + (isCompact, isNative, inlineDiff, expected) => { + expect(resolveChangesPresentation({ isTree: true, isCompact, isNative, inlineDiff })).toBe( + expected, + ); + expect(resolveChangesPresentation({ isTree: false, isCompact, isNative, inlineDiff })).toBe( + "diff", + ); + }, +); diff --git a/packages/app/src/panels/changes/presentation.ts b/packages/app/src/panels/changes/presentation.ts new file mode 100644 index 0000000000..f3da9a405d --- /dev/null +++ b/packages/app/src/panels/changes/presentation.ts @@ -0,0 +1,9 @@ +export function resolveChangesPresentation(input: { + isTree: boolean; + inlineDiff: boolean; + isCompact: boolean; + isNative: boolean; +}): "tree" | "diff" | "combined" { + if (!input.isTree) return "diff"; + return input.isCompact || input.isNative || input.inlineDiff ? "combined" : "tree"; +} diff --git a/packages/app/src/panels/diff-panel.tsx b/packages/app/src/panels/diff-panel.tsx index 1297b278bb..b6fb30454f 100644 --- a/packages/app/src/panels/diff-panel.tsx +++ b/packages/app/src/panels/diff-panel.tsx @@ -1,3 +1,4 @@ +import { resolveChangesPresentation } from "./changes/presentation"; import { useCallback, useMemo, type ReactNode } from "react"; import { Text, View } from "react-native"; import { useTranslation } from "react-i18next"; @@ -7,7 +8,7 @@ import invariant from "tiny-invariant"; import { useRetainedPanelActive } from "@/components/retained-panel"; import { useIsCompactFormFactor } from "@/constants/layout"; import { PaneContentToolbar } from "@/components/ui/pane-content-toolbar"; -import { isWeb } from "@/constants/platform"; +import { isWeb, isNative } from "@/constants/platform"; import { DiffDocument } from "@/git/diff-document"; import { ChangesSurface, DiffLayoutToggle, resolveDiffLayout } from "@/git/diff-pane"; import { useCommitDiffFiles } from "@/git/use-diff-files"; @@ -76,14 +77,6 @@ function PanelState({ ); } -function resolveChangesPresentation( - isTree: boolean, - inlineDiff: boolean, -): "tree" | "diff" | "combined" { - if (!isTree) return "diff"; - return inlineDiff ? "combined" : "tree"; -} - function ChangesPanel() { const { t } = useTranslation(); const { serverId, workspaceId, tabId, target, openPreferredTarget, openTargetToSide } = @@ -98,6 +91,7 @@ function ChangesPanel() { "ChangesPanel requires working_diff or changes_tree target", ); const isTree = target.kind === "changes_tree"; + const isCompact = useIsCompactFormFactor(); const handleOpenFile = useCallback( (path: string) => openPreferredTarget({ kind: "file", path }, isTree ? "diffs" : "diffFiles"), @@ -122,7 +116,12 @@ function ChangesPanel() { return ; } - const presentation = resolveChangesPresentation(isTree, preferences.inlineDiff); + const presentation = resolveChangesPresentation({ + isTree, + inlineDiff: preferences.inlineDiff, + isCompact, + isNative, + }); const testID = isTree ? "changes-tree-panel" : "working-diff-panel"; const profileId = isTree ? `ChangesTreePanel:${tabId}` : `WorkingDiffPanel:${tabId}`; diff --git a/packages/app/src/panels/pull-request-panel.tsx b/packages/app/src/panels/pull-request-panel.tsx index 53a6af8bd0..3d2fb92a50 100644 --- a/packages/app/src/panels/pull-request-panel.tsx +++ b/packages/app/src/panels/pull-request-panel.tsx @@ -1,21 +1,16 @@ +import { useRetainedPullRequestData } from "./pull-request/data"; +import { + pullRequestPanelPresentation, + usePullRequestPanelDescriptor, +} from "./pull-request/descriptor"; import { Text, View } from "react-native"; -import { GitPullRequest } from "lucide-react-native"; -import { withUnistyles } from "react-native-unistyles"; import { useTranslation } from "react-i18next"; import invariant from "tiny-invariant"; -import { formatPrTabLabel } from "@/git/pull-request-panel"; import { usePaneContext } from "@/panels/pane-context"; -import { definePanel, type PanelPresentation } from "@/panels/panel-registry"; -import { PullRequestContent, usePullRequestData } from "@/panels/pull-request"; +import { definePanel } from "@/panels/panel-registry"; +import { PullRequestContent } from "@/panels/pull-request"; import { useWorkspaceDirectory } from "@/stores/session-store-hooks"; -const ThemedGitPullRequest = withUnistyles(GitPullRequest); -const pullRequestPanelPresentation = { - label: (t) => t("panels.pullRequest.label"), - subtitle: (t) => t("panels.pullRequest.subtitle"), - tooltip: (t) => t("panels.pullRequest.label"), - icon: ThemedGitPullRequest, -} satisfies PanelPresentation; const CENTERED_PADDED_STYLE = { flex: 1, alignItems: "center", @@ -23,33 +18,12 @@ const CENTERED_PADDED_STYLE = { padding: 16, } as const; -function usePullRequestPanelDescriptor( - _target: { kind: "pull_request" }, - context: { serverId: string; workspaceId: string }, -) { - const { t } = useTranslation(); - const cwd = useWorkspaceDirectory(context.serverId, context.workspaceId) ?? ""; - const prPane = usePullRequestData({ serverId: context.serverId, cwd, timelineEnabled: false }); - const label = - prPane.prNumber === null - ? pullRequestPanelPresentation.label(t) - : formatPrTabLabel(prPane.prNumber); - return { - label, - subtitle: pullRequestPanelPresentation.subtitle(t), - tooltip: label, - titleState: prPane.isLoading ? ("loading" as const) : ("ready" as const), - icon: pullRequestPanelPresentation.icon, - statusBucket: null, - }; -} - function PullRequestPanel() { const { t } = useTranslation(); const { serverId, workspaceId, target } = usePaneContext(); const cwd = useWorkspaceDirectory(serverId, workspaceId) ?? ""; invariant(target.kind === "pull_request", "PullRequestPanel requires pull_request target"); - const prPane = usePullRequestData({ serverId, cwd }); + const prPane = useRetainedPullRequestData({ serverId, cwd }, "content"); if (!cwd) { return ( diff --git a/packages/app/src/panels/pull-request/activity.integration.test.tsx b/packages/app/src/panels/pull-request/activity.integration.test.tsx new file mode 100644 index 0000000000..2f2b97aab2 --- /dev/null +++ b/packages/app/src/panels/pull-request/activity.integration.test.tsx @@ -0,0 +1,249 @@ +/** @vitest-environment jsdom */ +import { ToastApiProvider } from "@/contexts/toast-api-context"; +import { act, useCallback, type ReactNode } from "react"; +import { createRoot } from "react-dom/client"; +import { waitFor } from "@testing-library/dom"; +Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true }); +const noop = () => {}; +const toastApi = { show: noop, error: noop, copied: noop }; +const roots: ReturnType[] = []; +function render(children: ReactNode) { + const container = document.createElement("div"); + document.body.appendChild(container); + const root = createRoot(container); + roots.push(root); + act(() => root.render(children)); + return { + rerender: (next: ReactNode) => act(() => root.render(next)), + unmount: () => act(() => root.unmount()), + }; +} +function cleanup() { + for (const root of roots.splice(0)) act(() => root.unmount()); + document.body.replaceChildren(); +} + +import { QueryClient, QueryClientProvider, onlineManager } from "@tanstack/react-query"; +import { afterEach, beforeEach, expect, it } from "vitest"; +import { RetainedPanelActivity } from "@/components/retained-panel"; +import { + PullRequestConnectionProvider, + type PullRequestConnection, +} from "@/git/pull-request-connection"; +import { usePullRequestPanelDescriptor } from "./descriptor"; +import { useRetainedPullRequestData } from "./data"; +import { useWorkspacePullRequestDiscovery } from "./discovery"; +import { useSessionStore } from "@/stores/session-store"; +import { collectAllTabs, useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; +const serverId = "pr-demand", + workspaceId = "workspace", + workspaceKey = `${serverId}:${workspaceId}`, + cwd = "/repo"; +function Content() { + const data = useRetainedPullRequestData({ serverId, cwd }, "content"); + return {data.data?.title}; +} +function Rail() { + const descriptor = usePullRequestPanelDescriptor( + { kind: "pull_request" }, + { serverId, workspaceId }, + ); + return {descriptor.label}; +} +function Discovery({ active, workspaceActive }: { active: boolean; workspaceActive: boolean }) { + useWorkspacePullRequestDiscovery({ + workspaceKey, + serverId, + cwd, + workspaceActive, + isGit: true, + layoutMode: "single-pane", + explorerOpen: active, + }); + return null; +} +function createSource() { + const calls = { status: 0, timeline: 0 }; + const client: NonNullable = { + async checkoutPrStatus() { + calls.status++; + return { + cwd, + forge: "github", + requestId: "status", + error: null, + githubFeaturesEnabled: true, + status: { + forge: "github", + number: 42, + url: "https://github.com/acme/repo/pull/42", + title: "Retained PR", + state: "open", + baseRefName: "main", + headRefName: "feature", + isMerged: false, + isDraft: false, + mergeable: "UNKNOWN", + checks: [], + reviewDecision: null, + repoOwner: "acme", + repoName: "repo", + }, + }; + }, + async pullRequestTimeline() { + calls.timeline++; + return { + cwd, + requestId: "timeline", + prNumber: 42, + items: [], + truncated: false, + error: null, + githubFeaturesEnabled: true, + }; + }, + }; + return { client, calls }; +} +beforeEach(async () => { + useSessionStore.getState().initializeSession(serverId, null); + useSessionStore.getState().setWorkspaces( + serverId, + new Map([ + [ + workspaceId, + { + id: workspaceId, + projectId: "project", + projectDisplayName: "Project", + projectCustomName: null, + projectRootPath: cwd, + workspaceDirectory: cwd, + projectKind: "git", + workspaceKind: "local_checkout", + name: "main", + status: "done", + statusEnteredAt: null, + archivingAt: null, + diffStat: null, + scripts: [], + }, + ], + ]), + ); + await useWorkspaceLayoutStore.persist.rehydrate(); + useWorkspaceLayoutStore.setState({ + layoutMode: "single-pane", + layoutByWorkspace: {}, + explorerSidebarPaneIdByWorkspace: {}, + }); +}); +afterEach(() => { + cleanup(); + useSessionStore.getState().clearSession(serverId); + onlineManager.setOnline(true); +}); +it("runs real PR descriptor/content/discovery hooks through hidden invalidation, reconnect and close opt-out", async () => { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); + const source = createSource(); + useWorkspaceLayoutStore + .getState() + .openTab({ workspaceKey, target: { kind: "files" }, intent: "reveal" }); + function Tree({ + surface, + content, + otherRail = false, + connected = true, + workspaceActive = true, + }: { + surface: boolean; + content: boolean; + otherRail?: boolean; + connected?: boolean; + workspaceActive?: boolean; + }) { + const connection = useCallback( + () => ({ client: source.client, isConnected: connected }), + [connected], + ); + return ( + + + + + + + + + + + + {otherRail ? : null} + + + ); + } + const tabs = () => + collectAllTabs(useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey].root); + const view = render(); + expect(source.calls).toEqual({ status: 0, timeline: 0 }); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 1, timeline: 0 })); + await waitFor(() => expect(tabs().some((tab) => tab.target.kind === "pull_request")).toBe(true)); + expect(useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey].focusedPaneId).toBe( + "main", + ); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 1, timeline: 1 })); + await waitFor(() => expect(queryClient.isFetching()).toBe(0)); + await waitFor(() => + expect(document.querySelector('[data-testid="content"]')?.textContent).toBe("Retained PR"), + ); + const cached = queryClient + .getQueryCache() + .getAll() + .map((query) => query.state.data); + view.rerender(); + await act(async () => { + onlineManager.setOnline(false); + await queryClient.invalidateQueries(); + onlineManager.setOnline(true); + }); + view.rerender(); + await act(async () => { + await new Promise((resolve) => setTimeout(resolve, 30)); + }); + expect(source.calls).toEqual({ status: 1, timeline: 1 }); + expect( + queryClient + .getQueryCache() + .getAll() + .map((query) => query.state.data), + ).toEqual(cached); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 2, timeline: 1 })); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 2, timeline: 2 })); + await waitFor(() => expect(queryClient.isFetching()).toBe(0)); + const prTab = tabs().find((tab) => tab.target.kind === "pull_request")!; + act(() => useWorkspaceLayoutStore.getState().closeTab(workspaceKey, prTab.tabId)); + view.rerender(); + await act(async () => { + await queryClient.invalidateQueries(); + }); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 3, timeline: 2 })); + expect(tabs().some((tab) => tab.target.kind === "pull_request")).toBe(false); + await waitFor(() => expect(queryClient.isFetching()).toBe(0)); + view.rerender(); + await act(async () => { + await queryClient.invalidateQueries(); + }); + expect(source.calls).toEqual({ status: 3, timeline: 2 }); + view.rerender(); + await waitFor(() => expect(source.calls).toEqual({ status: 4, timeline: 3 })); + expect(tabs().some((tab) => tab.target.kind === "pull_request")).toBe(false); + view.unmount(); + queryClient.clear(); +}); diff --git a/packages/app/src/panels/pull-request/activity.test.ts b/packages/app/src/panels/pull-request/activity.test.ts new file mode 100644 index 0000000000..8177f49639 --- /dev/null +++ b/packages/app/src/panels/pull-request/activity.test.ts @@ -0,0 +1,51 @@ +import { QueryClient, QueryObserver } from "@tanstack/react-query"; +import { expect, it } from "vitest"; +import { pullRequestDemand, shouldDiscoverPullRequest } from "./activity"; + +it("stops retained PR summary and timeline demand, then catches up once on reopen", async () => { + const client = new QueryClient({ + defaultOptions: { queries: { retry: false, staleTime: Infinity } }, + }); + const calls = { status: 0, timeline: 0 }; + const options = (kind: "status" | "timeline", active: boolean, consumer: "rail" | "content") => ({ + queryKey: [kind], + queryFn: async () => ++calls[kind], + enabled: + kind === "status" + ? pullRequestDemand(active, consumer).enabled + : pullRequestDemand(active, consumer).timelineEnabled, + }); + const status = new QueryObserver(client, options("status", true, "content")); + const timeline = new QueryObserver(client, options("timeline", true, "content")); + const unsubscribe = [status.subscribe(() => {}), timeline.subscribe(() => {})]; + await Promise.all([status.refetch(), timeline.refetch()]); + expect(calls).toEqual({ status: 1, timeline: 1 }); + status.setOptions(options("status", false, "content")); + timeline.setOptions(options("timeline", false, "content")); + await client.invalidateQueries(); + expect(calls).toEqual({ status: 1, timeline: 1 }); + status.setOptions(options("status", true, "rail")); + timeline.setOptions(options("timeline", true, "rail")); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(calls).toEqual({ status: 2, timeline: 1 }); + timeline.setOptions(options("timeline", true, "content")); + await new Promise((resolve) => setTimeout(resolve, 0)); + expect(calls).toEqual({ status: 2, timeline: 2 }); + unsubscribe.forEach((stop) => stop()); + client.clear(); +}); + +it.each([ + [true, true, true, false, true], + [true, true, false, true, true], + [true, true, false, false, false], + [false, true, true, true, false], + [true, false, true, true, false], +])( + "budgets discovery independently of tab existence", + (workspaceActive, isGit, splitLayout, explorerActive, expected) => { + expect(shouldDiscoverPullRequest({ workspaceActive, isGit, splitLayout, explorerActive })).toBe( + expected, + ); + }, +); diff --git a/packages/app/src/panels/pull-request/activity.ts b/packages/app/src/panels/pull-request/activity.ts new file mode 100644 index 0000000000..4b83308521 --- /dev/null +++ b/packages/app/src/panels/pull-request/activity.ts @@ -0,0 +1,12 @@ +/** A rail needs summary status; the selected content additionally needs timeline data. */ +export function pullRequestDemand(active: boolean, consumer: "rail" | "content") { + return { enabled: active, timelineEnabled: active && consumer === "content" }; +} +export function shouldDiscoverPullRequest(input: { + workspaceActive: boolean; + isGit: boolean; + splitLayout: boolean; + explorerActive: boolean; +}): boolean { + return input.workspaceActive && input.isGit && (input.splitLayout || input.explorerActive); +} diff --git a/packages/app/src/panels/pull-request/data.ts b/packages/app/src/panels/pull-request/data.ts new file mode 100644 index 0000000000..5ec0bcfc31 --- /dev/null +++ b/packages/app/src/panels/pull-request/data.ts @@ -0,0 +1,11 @@ +import { useRetainedPanelActive } from "@/components/retained-panel"; +import { usePrPaneData } from "@/git/pull-request-panel/use-data"; +import { pullRequestDemand } from "./activity"; +export { usePrPaneData as usePullRequestData } from "@/git/pull-request-panel/use-data"; +export function useRetainedPullRequestData( + input: { serverId: string; cwd: string }, + role: "rail" | "content", +) { + const active = useRetainedPanelActive(); + return usePrPaneData({ ...input, ...pullRequestDemand(active, role) }); +} diff --git a/packages/app/src/panels/pull-request/descriptor.tsx b/packages/app/src/panels/pull-request/descriptor.tsx new file mode 100644 index 0000000000..6eb9f20ed2 --- /dev/null +++ b/packages/app/src/panels/pull-request/descriptor.tsx @@ -0,0 +1,40 @@ +import { GitPullRequest } from "lucide-react-native"; +import { withUnistyles } from "react-native-unistyles"; +import { useTranslation } from "react-i18next"; +import { formatPrTabLabel } from "@/git/pull-request-panel/tab-label"; +import type { PanelPresentation } from "@/panels/panel-registry"; +import { useWorkspaceDirectory } from "@/stores/session-store-hooks"; +import { useRetainedPullRequestData } from "./data"; +const ThemedGitPullRequest = withUnistyles(GitPullRequest); +export const pullRequestPanelPresentation = { + label: (t) => t("panels.pullRequest.label"), + subtitle: (t) => t("panels.pullRequest.subtitle"), + tooltip: (t) => t("panels.pullRequest.label"), + icon: ThemedGitPullRequest, +} satisfies PanelPresentation; +export function usePullRequestPanelDescriptor( + _target: { kind: "pull_request" }, + context: { serverId: string; workspaceId: string }, +) { + const { t } = useTranslation(); + const cwd = useWorkspaceDirectory(context.serverId, context.workspaceId) ?? ""; + const prPane = useRetainedPullRequestData( + { + serverId: context.serverId, + cwd, + }, + "rail", + ); + const label = + prPane.prNumber === null + ? pullRequestPanelPresentation.label(t) + : formatPrTabLabel(prPane.prNumber); + return { + label, + subtitle: pullRequestPanelPresentation.subtitle(t), + tooltip: label, + titleState: prPane.isLoading ? ("loading" as const) : ("ready" as const), + icon: pullRequestPanelPresentation.icon, + statusBucket: null, + }; +} diff --git a/packages/app/src/panels/pull-request/discovery.ts b/packages/app/src/panels/pull-request/discovery.ts new file mode 100644 index 0000000000..43df9c870f --- /dev/null +++ b/packages/app/src/panels/pull-request/discovery.ts @@ -0,0 +1,65 @@ +import { useEffect } from "react"; +import { useIsMobilePanelActive } from "@/mobile-panels/provider"; +import { shouldDiscoverPullRequest } from "./activity"; +import { useCheckoutPrStatusQuery } from "@/git/use-pr-status-query"; +import { useSettings } from "@/hooks/use-settings"; +import { + useWorkspaceLayoutStore, + useWorkspaceLayoutStoreHydrated, +} from "@/stores/workspace-layout-store"; +import { autoOpenWorkspacePullRequest } from "@/workspace-tabs/open-supporting-view"; +import { getPullRequestIdentity } from "./state"; +/** Workspace discovery remains independent from whether an ordinary PR tab exists. */ +export function useWorkspacePullRequestDiscovery(input: { + workspaceKey: string | null; + serverId: string; + cwd: string | null; + workspaceActive: boolean; + isGit: boolean; + layoutMode: "compact" | "single-pane" | "split-panes"; + explorerOpen: boolean; +}): boolean { + const settledExplorerActive = useIsMobilePanelActive("file-explorer"); + const enabled = shouldDiscoverPullRequest({ + workspaceActive: input.workspaceActive, + isGit: input.isGit, + splitLayout: input.layoutMode === "split-panes", + explorerActive: input.layoutMode === "compact" ? settledExplorerActive : input.explorerOpen, + }); + const hasPullRequest = useHasPullRequest({ serverId: input.serverId, cwd: input.cwd, enabled }); + usePullRequestAutoAdd({ workspaceKey: input.workspaceKey, hasPullRequest, enabled }); + return hasPullRequest; +} + +/** + * Whether this workspace's branch has a pull request. + */ +export function useHasPullRequest(input: { + serverId: string; + cwd: string | null; + enabled: boolean; +}): boolean { + const status = useCheckoutPrStatusQuery({ + serverId: input.serverId, + cwd: input.cwd || "", + enabled: input.enabled, + }).status; + return getPullRequestIdentity(status) !== null; +} + +/** Connects desktop PR detection to the persisted layout after hydration. */ +export function usePullRequestAutoAdd(input: { + workspaceKey: string | null; + hasPullRequest: boolean; + enabled: boolean; +}): void { + const hydrated = useWorkspaceLayoutStoreHydrated(); + const preferredDestination = useSettings((settings) => settings.pullRequestOpenLocation); + const splitLayout = useWorkspaceLayoutStore((state) => state.layoutMode === "split-panes"); + const destination = splitLayout ? preferredDestination : "explorer"; + useEffect(() => { + if (hydrated && input.enabled && input.hasPullRequest) { + autoOpenWorkspacePullRequest({ workspaceKey: input.workspaceKey, destination }); + } + }, [hydrated, input.enabled, input.hasPullRequest, input.workspaceKey, destination]); +} diff --git a/packages/app/src/panels/pull-request/index.tsx b/packages/app/src/panels/pull-request/index.tsx index 148da86914..56ce378a4e 100644 --- a/packages/app/src/panels/pull-request/index.tsx +++ b/packages/app/src/panels/pull-request/index.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect } from "react"; +import { useCallback } from "react"; import { Text, View } from "react-native"; import { useTranslation } from "react-i18next"; import { StyleSheet } from "react-native-unistyles"; @@ -9,47 +9,16 @@ import { PullRequestPane, PullRequestPaneError, PullRequestPaneSkeleton, - usePrPaneData, } from "@/git/pull-request-panel"; import type { UsePrPaneDataResult } from "@/git/pull-request-panel/use-data"; -import { useCheckoutPrStatusQuery } from "@/git/use-pr-status-query"; -import { useSettings } from "@/hooks/use-settings"; -import { useWorkspaceLayoutStoreHydrated } from "@/stores/workspace-layout-store"; -import { autoOpenWorkspacePullRequest } from "@/workspace-tabs/open-supporting-view"; - -import { getPullRequestIdentity, resolvePullRequestContentState } from "./state"; - -/** - * Whether this workspace's branch has a pull request. - */ -export function useHasPullRequest(input: { - serverId: string; - cwd: string | null; - enabled: boolean; -}): boolean { - const status = useCheckoutPrStatusQuery({ - serverId: input.serverId, - cwd: input.cwd || "", - enabled: input.enabled, - }).status; - return getPullRequestIdentity(status) !== null; -} - -/** Connects desktop PR detection to the persisted layout after hydration. */ -export function usePullRequestAutoAdd(input: { - workspaceKey: string | null; - hasPullRequest: boolean; - enabled: boolean; -}): void { - const hydrated = useWorkspaceLayoutStoreHydrated(); - const destination = useSettings((settings) => settings.pullRequestOpenLocation); - useEffect(() => { - if (hydrated && input.enabled && input.hasPullRequest) { - autoOpenWorkspacePullRequest({ workspaceKey: input.workspaceKey, destination }); - } - }, [hydrated, input.enabled, input.hasPullRequest, input.workspaceKey, destination]); -} +import { resolvePullRequestContentState } from "./state"; +export { + useWorkspacePullRequestDiscovery, + useHasPullRequest, + usePullRequestAutoAdd, +} from "./discovery"; +export { usePullRequestData } from "./data"; export function PullRequestContent(input: { serverId: string; @@ -96,15 +65,6 @@ export function PullRequestContent(input: { ); } -export function usePullRequestData(input: { - serverId: string; - cwd: string; - enabled?: boolean; - timelineEnabled?: boolean; -}) { - return usePrPaneData(input); -} - const styles = StyleSheet.create((theme) => ({ empty: { flex: 1, diff --git a/packages/app/src/panels/retained-chat-content.browser.test.tsx b/packages/app/src/panels/retained-chat-content.browser.test.tsx new file mode 100644 index 0000000000..cba12e3cbd --- /dev/null +++ b/packages/app/src/panels/retained-chat-content.browser.test.tsx @@ -0,0 +1,101 @@ +import { act, useLayoutEffect, useState, useSyncExternalStore } from "react"; +import { createRoot, type Root } from "react-dom/client"; +import { afterEach, beforeEach, expect, it } from "vitest"; +import { RetainedPanelActivity } from "@/components/retained-panel"; +import { RetainedChatContent as NativeChat } from "./retained-chat-content.native"; +import { RetainedChatContent as WebChat } from "./retained-chat-content.web"; +import { useMountedTabSet } from "@/screens/workspace/use-mounted-tab-set"; + +Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true }); +let root: Root; +let container: HTMLDivElement; +beforeEach(() => { + container = document.createElement("div"); + document.body.appendChild(container); + root = createRoot(container); +}); +afterEach(() => { + act(() => root.unmount()); + container.remove(); +}); + +for (const [runtime, Chat] of [ + ["native", NativeChat], + ["web", WebChat], +] as const) { + it(`${runtime} retains local state while applying its hidden rendering policy`, async () => { + let version = 0, + commits = 0, + mounts = 0; + const listeners = new Set<() => void>(); + const subscribe = (listener: () => void) => { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; + }; + function Content() { + const value = useSyncExternalStore(subscribe, () => version); + const [local] = useState(() => "unsaved-local-draft"); + useLayoutEffect(() => { + mounts++; + }, []); + useLayoutEffect(() => { + commits++; + }); + return ( + + {local}:{value} + + ); + } + const render = (active: boolean) => + act(() => + root.render( + + + + + , + ), + ); + render(true); + render(false); + const hiddenCommits = commits; + await act(async () => { + version++; + listeners.forEach((listener) => listener()); + }); + expect(commits - hiddenCommits).toBe(runtime === "native" ? 1 : 0); + render(true); + expect(container.textContent).toBe("unsaved-local-draft:1"); + // Web Suspense reruns layout effects on reveal; local state survives in both runtimes. + expect(mounts).toBe(runtime === "native" ? 1 : 2); + }); +} + +it("retains modified panels beyond the LRU cap and evicts them normally after save", () => { + let mounted: string[] = []; + const allTabIds = ["a", "b", "c", "d", "e"]; + function Host({ active, modified }: { active: string; modified: Set }) { + const { mountedTabIds } = useMountedTabSet({ + activeTabId: active, + allTabIds, + retainedTabIds: modified, + cap: 3, + }); + mounted = [...mountedTabIds]; + return null; + } + const render = (active: string, modified = new Set()) => + act(() => root.render()); + render("a"); + render("b"); + render("c"); + render("d"); + expect(mounted).toEqual(["d", "c", "b"]); + render("e", new Set(["a", "b", "c", "d"])); + expect(mounted).toEqual(["e", "a", "b", "c", "d"]); + render("e"); + expect(mounted).toEqual(["e", "a", "b"]); +}); diff --git a/packages/app/src/panels/retained-chat-content.native.tsx b/packages/app/src/panels/retained-chat-content.native.tsx new file mode 100644 index 0000000000..0ed1d2dfc8 --- /dev/null +++ b/packages/app/src/panels/retained-chat-content.native.tsx @@ -0,0 +1,11 @@ +import type { ReactNode } from "react"; + +/** + * Native: a hidden chat stays mounted and keeps rendering. Suspending a retained + * native subtree hides its host views, tears down layout effects, and detaches + * refs, which changes Fabric ownership (docs/mobile-panels.md). Activity-gated + * work already stops through the retained-panel signal. + */ +export function RetainedChatContent({ children }: { children: ReactNode }) { + return children; +} diff --git a/packages/app/src/panels/retained-chat-content.tsx b/packages/app/src/panels/retained-chat-content.tsx index 0ed1d2dfc8..31117e4655 100644 --- a/packages/app/src/panels/retained-chat-content.tsx +++ b/packages/app/src/panels/retained-chat-content.tsx @@ -1,11 +1 @@ -import type { ReactNode } from "react"; - -/** - * Native: a hidden chat stays mounted and keeps rendering. Suspending a retained - * native subtree hides its host views, tears down layout effects, and detaches - * refs, which changes Fabric ownership (docs/mobile-panels.md). Activity-gated - * work already stops through the retained-panel signal. - */ -export function RetainedChatContent({ children }: { children: ReactNode }) { - return children; -} +export { RetainedChatContent } from "./retained-chat-content.native"; diff --git a/packages/app/src/panels/terminal-panel.tsx b/packages/app/src/panels/terminal-panel.tsx index 8082bd36e5..3492c40cac 100644 --- a/packages/app/src/panels/terminal-panel.tsx +++ b/packages/app/src/panels/terminal-panel.tsx @@ -11,7 +11,9 @@ import { usePaneContext, usePaneFocus } from "@/panels/pane-context"; import { definePanel, type PanelDescriptor } from "@/panels/panel-registry"; import { queryClient } from "@/data/query-client"; import { buildTerminalsQueryKey } from "@/screens/workspace/terminals/state"; -import { usePanelStore } from "@/stores/panel-store"; +import { showExplorerSidebar } from "@/workspace-tabs/explorer-sidebar"; +import { buildWorkspaceTabPersistenceKey } from "@/workspace-tabs/model"; +import { useIsCompactFormFactor } from "@/constants/layout"; import { useSessionStore } from "@/stores/session-store"; import { useWorkspaceDirectory, useWorkspaceFields } from "@/stores/session-store-hooks"; @@ -80,17 +82,18 @@ function TerminalPanel() { const { isWorkspaceFocused, isPaneFocused } = usePaneFocus(); const workspaceFields = useWorkspaceFields(serverId, workspaceId, (w) => ({ workspaceDirectory: w.workspaceDirectory, - isGitCheckout: w.projectKind === "git", })); const workspaceDirectory = workspaceFields?.workspaceDirectory || null; - const isGitCheckout = workspaceFields?.isGitCheckout ?? false; - const openCompactFileExplorer = usePanelStore((state) => state.openCompactFileExplorer); + const isCompact = useIsCompactFormFactor(); const handleOpenFileExplorer = useCallback(() => { if (!workspaceDirectory) { return; } - openCompactFileExplorer({ serverId, cwd: workspaceDirectory, isGit: isGitCheckout }); - }, [isGitCheckout, openCompactFileExplorer, serverId, workspaceDirectory]); + showExplorerSidebar({ + isCompact, + workspaceKey: buildWorkspaceTabPersistenceKey({ serverId, workspaceId }), + }); + }, [isCompact, serverId, workspaceId, workspaceDirectory]); invariant(target.kind === "terminal", "TerminalPanel requires terminal target"); if (!workspaceDirectory) { diff --git a/packages/app/src/panels/use-add-file-to-chat.ts b/packages/app/src/panels/use-add-file-to-chat.ts index 8261a2b0a9..f5cbd99287 100644 --- a/packages/app/src/panels/use-add-file-to-chat.ts +++ b/packages/app/src/panels/use-add-file-to-chat.ts @@ -1,3 +1,4 @@ +import { revealWorkspaceTab } from "@/workspace-tabs/navigation"; import { useCallback, useMemo } from "react"; import { createWorkspaceFileAttachment } from "@/attachments/workspace-file"; import { resolveFocusedChatTarget } from "@/composer/focused-chat-target"; @@ -12,7 +13,6 @@ export function useAddFileToChat(input: { serverId: string; workspaceId?: string const layout = useWorkspaceLayoutStore((state) => workspaceKey ? state.layoutByWorkspace[workspaceKey] : undefined, ); - const focusTab = useWorkspaceLayoutStore((state) => state.focusTab); const focusedChat = useMemo( () => resolveFocusedChatTarget({ serverId: input.serverId, layout }), [input.serverId, layout], @@ -26,9 +26,9 @@ export function useAddFileToChat(input: { serverId: string; workspaceId?: string draftKey: focusedChat.draftKey, attachment: createWorkspaceFileAttachment({ path: filePath }), }); - focusTab(workspaceKey, focusedChat.tabId); + revealWorkspaceTab(workspaceKey, focusedChat.tabId); }, - [focusTab, focusedChat, workspaceKey], + [focusedChat, workspaceKey], ); return { addFile, canAddToChat: focusedChat !== null }; } diff --git a/packages/app/src/screens/project-settings-screen.tsx b/packages/app/src/screens/project-settings-screen.tsx index 50c81a05fd..a23784f5dc 100644 --- a/packages/app/src/screens/project-settings-screen.tsx +++ b/packages/app/src/screens/project-settings-screen.tsx @@ -2,7 +2,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import type { TFunction } from "i18next"; import { useTranslation } from "react-i18next"; import { Pressable, Text, View } from "react-native"; -import { useFocusEffect } from "@react-navigation/native"; +import { useFocusEffect } from "expo-router/react-navigation"; import { StyleSheet } from "react-native-unistyles"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowLeft, MoreVertical, Pencil, Plus } from "lucide-react-native"; diff --git a/packages/app/src/screens/schedules-screen.tsx b/packages/app/src/screens/schedules-screen.tsx index ce2f8b9dfd..3c76db14f2 100644 --- a/packages/app/src/screens/schedules-screen.tsx +++ b/packages/app/src/screens/schedules-screen.tsx @@ -7,7 +7,7 @@ import { type ReactElement, } from "react"; import { ScrollView, Text, View } from "react-native"; -import { useIsFocused } from "@react-navigation/native"; +import { useIsFocused } from "expo-router/react-navigation"; import { CalendarClock, Plus } from "lucide-react-native"; import { StyleSheet } from "react-native-unistyles"; import { MenuHeader } from "@/components/headers/menu-header"; diff --git a/packages/app/src/screens/sessions-screen.tsx b/packages/app/src/screens/sessions-screen.tsx index bcd1e4f740..5a9f765843 100644 --- a/packages/app/src/screens/sessions-screen.tsx +++ b/packages/app/src/screens/sessions-screen.tsx @@ -1,6 +1,6 @@ import { useMemo, useState, useCallback, useEffect, type ReactElement } from "react"; import { View, Text } from "react-native"; -import { useIsFocused } from "@react-navigation/native"; +import { useIsFocused } from "expo-router/react-navigation"; import { router } from "expo-router"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { ChevronLeft, Import } from "lucide-react-native"; diff --git a/packages/app/src/screens/settings-screen.tsx b/packages/app/src/screens/settings-screen.tsx index 31f5058940..4bf111d276 100644 --- a/packages/app/src/screens/settings-screen.tsx +++ b/packages/app/src/screens/settings-screen.tsx @@ -9,7 +9,7 @@ import { type PressableStateCallbackType, } from "react-native"; import { useRouter } from "expo-router"; -import { useFocusEffect } from "@react-navigation/native"; +import { useFocusEffect } from "expo-router/react-navigation"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { useTranslation } from "react-i18next"; diff --git a/packages/app/src/screens/settings/keyboard-shortcuts-section.tsx b/packages/app/src/screens/settings/keyboard-shortcuts-section.tsx index 6a8459fc3f..e00045e957 100644 --- a/packages/app/src/screens/settings/keyboard-shortcuts-section.tsx +++ b/packages/app/src/screens/settings/keyboard-shortcuts-section.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { View, Text, type PressableStateCallbackType } from "react-native"; -import { useIsFocused } from "@react-navigation/native"; +import { useIsFocused } from "expo-router/react-navigation"; import { MoreHorizontal, Pencil, Undo2, X } from "lucide-react-native"; import { StyleSheet, withUnistyles } from "react-native-unistyles"; import type { Theme } from "@/styles/theme"; diff --git a/packages/app/src/screens/workspace/explorer-sidebar.tsx b/packages/app/src/screens/workspace/explorer-sidebar.tsx index 175be3695b..e39106b65b 100644 --- a/packages/app/src/screens/workspace/explorer-sidebar.tsx +++ b/packages/app/src/screens/workspace/explorer-sidebar.tsx @@ -1,9 +1,9 @@ import { useCallback, useMemo, type ReactNode } from "react"; import { View } from "react-native"; +import { useWorkspaceTabDrag } from "@/components/workspace-tab-drag-context"; import { StyleSheet } from "react-native-unistyles"; import { RetainedPanel } from "@/components/retained-panel"; import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region"; -import type { TabDropPreview } from "@/components/split-container-tab-drop-preview"; import { WorkspacePanelHost } from "@/screens/workspace/workspace-panel-host"; import { deriveWorkspacePaneState } from "@/screens/workspace/workspace-pane-state"; import { @@ -39,8 +39,6 @@ interface ExplorerSidebarDockProps extends Pick< normalizedWorkspaceId: string; isWorkspaceFocused: boolean; closingTabIds: Set; - activeDragTabId: string | null; - tabDropPreview: TabDropPreview | null; onSelectTab: (paneId: string, tabId: string) => void; onCloseTab: (tabId: string) => Promise | void; onReorderTabsInPane: (paneId: string, tabIds: string[]) => void; @@ -59,8 +57,6 @@ export function ExplorerSidebarDock({ normalizedWorkspaceId, isWorkspaceFocused, closingTabIds, - activeDragTabId, - tabDropPreview, onSelectTab, onCloseTab, onCreateNewTab, @@ -80,6 +76,7 @@ export function ExplorerSidebarDock({ buildPaneContentModel, headerAction, }: ExplorerSidebarDockProps) { + const { activeDragTabId, tabDropPreview, externalDndContext } = useWorkspaceTabDrag(); const paneState = useMemo(() => deriveWorkspacePaneState({ pane, tabs: uiTabs }), [pane, uiTabs]); const tabs = useMemo(() => paneState.tabs.map((tab) => tab.descriptor), [paneState.tabs]); const activeTabId = paneState.activeTabId; @@ -144,7 +141,7 @@ export function ExplorerSidebarDock({ onCloseOtherTabs={handleCloseOtherTabs} focusModeEnabled={false} onExitFocusMode={onExitFocusMode} - externalDndContext + externalDndContext={externalDndContext} paneId={pane.id} tabs={tabItems} normalizedServerId={normalizedServerId} diff --git a/packages/app/src/screens/workspace/explorer-sidebar/frame-props.ts b/packages/app/src/screens/workspace/explorer-sidebar/frame-props.ts new file mode 100644 index 0000000000..d99686cd7f --- /dev/null +++ b/packages/app/src/screens/workspace/explorer-sidebar/frame-props.ts @@ -0,0 +1,10 @@ +import type { ReactNode } from "react"; +export interface ExplorerFrameProps { + children: ReactNode; + presentation: "overlay" | "dock"; + persistenceKey: string; + containerWidth: number; + isOpen: boolean; + isWorkspaceActive: boolean; + surfaceColor?: string; +} diff --git a/packages/app/src/screens/workspace/explorer-sidebar/frame.tsx b/packages/app/src/screens/workspace/explorer-sidebar/frame.tsx new file mode 100644 index 0000000000..f166233a2e --- /dev/null +++ b/packages/app/src/screens/workspace/explorer-sidebar/frame.tsx @@ -0,0 +1,68 @@ +import { useCallback } from "react"; +import { View } from "react-native"; +import { StyleSheet, withUnistyles } from "react-native-unistyles"; +import { + FileExplorerCloseGestureContext, + useCloseFileExplorerGesture, +} from "@/mobile-panels/gestures"; +import { useIsMobilePanelActive } from "@/mobile-panels/provider"; +import { MobilePanelOverlay } from "@/mobile-panels/presentation"; +import { RetainedPanelActivity } from "@/components/retained-panel"; +import { resolveExplorerSidebarWidth } from "@/components/explorer-sidebar-layout"; +import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; +import { useExplorerGeometry } from "./geometry"; +import type { ExplorerFrameProps } from "./frame-props"; + +function ExplorerFrameBase({ + children, + surfaceColor, + presentation, + isOpen, + isWorkspaceActive, + persistenceKey, + containerWidth, +}: ExplorerFrameProps) { + const overlay = presentation === "overlay"; + const settledOpen = useIsMobilePanelActive("file-explorer"); + const active = isWorkspaceActive && (overlay ? settledOpen : isOpen); + const resizeEnabled = isWorkspaceActive && !overlay && isOpen; + const { gesture, gestureRef } = useCloseFileExplorerGesture(isWorkspaceActive && overlay); + const storedWidth = useWorkspaceLayoutStore( + (state) => state.explorerSidebarWidthByWorkspace[persistenceKey], + ); + const resize = useWorkspaceLayoutStore((state) => state.resizeExplorerSidebar); + const onResize = useCallback( + (width: number) => resize(persistenceKey, width), + [persistenceKey, resize], + ); + const geometry = useExplorerGeometry({ + width: resolveExplorerSidebarWidth({ requestedWidth: storedWidth, containerWidth }), + containerWidth, + overlay, + resizeEnabled, + onResize, + }); + return ( + + + + + {resizeEnabled ? geometry.resizeHandle : null} + {children} + + + + + ); +} +export const ExplorerFrame = withUnistyles(ExplorerFrameBase, (theme) => ({ + surfaceColor: theme.colors.surfaceSidebar, +})); +const styles = StyleSheet.create({ content: { flex: 1, minHeight: 0 } }); diff --git a/packages/app/src/screens/workspace/explorer-sidebar/geometry-types.ts b/packages/app/src/screens/workspace/explorer-sidebar/geometry-types.ts new file mode 100644 index 0000000000..975dc721bd --- /dev/null +++ b/packages/app/src/screens/workspace/explorer-sidebar/geometry-types.ts @@ -0,0 +1,15 @@ +import type { ComponentProps, ReactNode } from "react"; +import type { StyleProp, ViewStyle } from "react-native"; +import type { MobilePanelOverlay } from "@/mobile-panels/presentation"; +export interface ExplorerGeometryInput { + width: number; + containerWidth: number; + overlay: boolean; + resizeEnabled: boolean; + onResize: (width: number) => void; +} +export interface ExplorerGeometry { + frameStyle: ComponentProps["frameStyle"]; + panelStyle: StyleProp; + resizeHandle: ReactNode; +} diff --git a/packages/app/src/screens/workspace/explorer-sidebar/geometry.tsx b/packages/app/src/screens/workspace/explorer-sidebar/geometry.tsx new file mode 100644 index 0000000000..4714467985 --- /dev/null +++ b/packages/app/src/screens/workspace/explorer-sidebar/geometry.tsx @@ -0,0 +1,86 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; +import { Gesture } from "react-native-gesture-handler"; +import { runOnJS, useAnimatedStyle, useSharedValue } from "react-native-reanimated"; +import { scheduleOnRN } from "react-native-worklets"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; +import { HEADER_TOP_PADDING_MOBILE } from "@/constants/layout"; +import { SidebarResizeHandle } from "@/components/sidebar-resize-handle"; +import { + SIDEBAR_RESIZE_ACTIVATION_OFFSET, + SIDEBAR_RESIZE_FAIL_OFFSET, +} from "@/components/sidebar-resize-handle-layout"; +import { resolveExplorerSidebarWidth } from "@/components/explorer-sidebar-layout"; +import type { ExplorerGeometryInput, ExplorerGeometry } from "./geometry-types"; +export function useExplorerGeometry({ + width, + containerWidth, + overlay, + resizeEnabled, + onResize, +}: ExplorerGeometryInput): ExplorerGeometry { + const insets = useSafeAreaInsets(); + const resizeWidth = useSharedValue(width); + const startWidth = useSharedValue(width); + const [resizePressed, setResizePressed] = useState(false); + useEffect(() => { + resizeWidth.value = width; + }, [resizeWidth, width]); + + const showResizeGrip = useCallback(() => setResizePressed(true), []); + const hideResizeGrip = useCallback(() => setResizePressed(false), []); + const resizeGesture = useMemo( + () => + Gesture.Pan() + .enabled(resizeEnabled) + .hitSlop({ left: 8, right: 8, top: 0, bottom: 0 }) + .onBegin(() => scheduleOnRN(showResizeGrip)) + .activeOffsetX([-SIDEBAR_RESIZE_ACTIVATION_OFFSET, SIDEBAR_RESIZE_ACTIVATION_OFFSET]) + .failOffsetY([-SIDEBAR_RESIZE_FAIL_OFFSET, SIDEBAR_RESIZE_FAIL_OFFSET]) + .onStart((event) => { + startWidth.value = width + event.translationX; + resizeWidth.value = width; + }) + .onUpdate((event) => { + resizeWidth.value = resolveExplorerSidebarWidth({ + requestedWidth: startWidth.value - event.translationX, + containerWidth, + }); + }) + .onEnd(() => runOnJS(onResize)(resizeWidth.value)) + .onFinalize(() => scheduleOnRN(hideResizeGrip)), + [ + resizeEnabled, + onResize, + containerWidth, + hideResizeGrip, + resizeWidth, + showResizeGrip, + startWidth, + width, + ], + ); + // Reanimated retains the last animated value when its style is removed. Keep this + // style attached across folding and explicitly size overlays to the workspace viewport. + const animatedWidthStyle = useAnimatedStyle( + () => ({ + width: overlay ? containerWidth : resizeWidth.value, + }), + [containerWidth, overlay], + ); + return { + frameStyle: animatedWidthStyle, + panelStyle: { + paddingTop: insets.top + (overlay ? HEADER_TOP_PADDING_MOBILE : 0), + paddingLeft: overlay ? insets.left : 0, + paddingRight: overlay ? insets.right : 0, + }, + resizeHandle: ( + + ), + }; +} diff --git a/packages/app/src/screens/workspace/explorer-sidebar/geometry.web.tsx b/packages/app/src/screens/workspace/explorer-sidebar/geometry.web.tsx new file mode 100644 index 0000000000..07e115923d --- /dev/null +++ b/packages/app/src/screens/workspace/explorer-sidebar/geometry.web.tsx @@ -0,0 +1,58 @@ +import { useCallback, useState } from "react"; +import { View, StyleSheet } from "react-native"; +import { inlineUnistylesStyle } from "@/styles/unistyles-inline-style"; +import { ResizeHandle } from "@/components/resize-handle"; +import { + resolveExplorerSidebarDockSizes, + resolveExplorerSidebarWidth, +} from "@/components/explorer-sidebar-layout"; +import type { ExplorerGeometryInput, ExplorerGeometry } from "./geometry-types"; +export function useExplorerGeometry({ + width, + containerWidth, + onResize, + overlay, +}: ExplorerGeometryInput): ExplorerGeometry { + const [previewWidth, setPreviewWidth] = useState(null); + const requestedWidth = previewWidth ?? width; + const sizes = resolveExplorerSidebarDockSizes({ requestedWidth, containerWidth }); + const preview = useCallback( + (_id: string, next: number[]) => { + setPreviewWidth( + resolveExplorerSidebarWidth({ requestedWidth: next[1] * containerWidth, containerWidth }), + ); + }, + [containerWidth], + ); + const commit = useCallback( + (_id: string, next: number[]) => { + setPreviewWidth(null); + onResize( + resolveExplorerSidebarWidth({ requestedWidth: next[1] * containerWidth, containerWidth }), + ); + }, + [containerWidth, onResize], + ); + return { + frameStyle: inlineUnistylesStyle({ width: overlay ? undefined : requestedWidth }), + panelStyle: undefined, + resizeHandle: ( + + + + ), + }; +} +const styles = StyleSheet.create({ + resize: { position: "absolute", left: 0, top: 0, bottom: 0, zIndex: 2, flexDirection: "row" }, +}); diff --git a/packages/app/src/screens/workspace/sheet-tabs.tsx b/packages/app/src/screens/workspace/sheet-tabs.tsx index 2b4e927a13..de13097503 100644 --- a/packages/app/src/screens/workspace/sheet-tabs.tsx +++ b/packages/app/src/screens/workspace/sheet-tabs.tsx @@ -1,5 +1,5 @@ import type { BottomSheetHandleProps } from "@gorhom/bottom-sheet"; -import { useIsFocused } from "@react-navigation/native"; +import { useIsFocused } from "expo-router/react-navigation"; import { type ComponentType, type FC, diff --git a/packages/app/src/screens/workspace/visible-agent-ids.test.ts b/packages/app/src/screens/workspace/visible-agent-ids.test.ts index d7b6f33a72..1378d6cc20 100644 --- a/packages/app/src/screens/workspace/visible-agent-ids.test.ts +++ b/packages/app/src/screens/workspace/visible-agent-ids.test.ts @@ -132,3 +132,36 @@ test("the agent shown in the workspace sheet is viewed alongside the pane under selectVisibleAgentIds({ layout, tabs, sheetTab, routeFocused: false, focusedPaneOnly: true }), ).toEqual([]); }); + +test("single-pane tablet includes its visible Explorer agent without including other splits", () => { + const layout: WorkspaceLayout = { + focusedPaneId: "main", + root: { + kind: "group", + group: { + id: "root", + direction: "horizontal", + sizes: [0.5, 0.25, 0.25], + children: [ + { kind: "pane", pane: { id: "main", tabIds: ["a"], focusedTabId: "a" } }, + { kind: "pane", pane: { id: "explorer", tabIds: ["b"], focusedTabId: "b" } }, + { kind: "pane", pane: { id: "other", tabIds: ["c"], focusedTabId: "c" } }, + ], + }, + }, + }; + const tabs: WorkspaceTab[] = ["a", "b", "c"].map((id) => ({ + tabId: id, + createdAt: 1, + target: { kind: "agent", agentId: id }, + })); + expect( + selectVisibleAgentIds({ + layout, + tabs, + routeFocused: true, + focusedPaneOnly: true, + explorerPaneId: "explorer", + }), + ).toEqual(["a", "b"]); +}); diff --git a/packages/app/src/screens/workspace/visible-agent-ids.ts b/packages/app/src/screens/workspace/visible-agent-ids.ts index 324d4121c3..8643e84940 100644 --- a/packages/app/src/screens/workspace/visible-agent-ids.ts +++ b/packages/app/src/screens/workspace/visible-agent-ids.ts @@ -10,12 +10,18 @@ export function selectVisibleAgentIds(input: { sheetTab?: WorkspaceTab | null; routeFocused: boolean; focusedPaneOnly: boolean; + explorerPaneId?: string | null; + explorerVisible?: boolean; }): string[] { if (!input.routeFocused || !input.layout) { return []; } const panes = input.focusedPaneOnly - ? collectAllPanes(input.layout.root).filter((pane) => pane.id === input.layout?.focusedPaneId) + ? collectAllPanes(input.layout.root).filter( + (pane) => + pane.id === input.layout?.focusedPaneId || + (input.explorerVisible !== false && pane.id === input.explorerPaneId), + ) : collectAllPanes(input.layout.root); const targets = panes.flatMap((pane) => { @@ -35,6 +41,8 @@ export function useVisibleAgentIds(input: { sheetTab: WorkspaceTab | null; routeFocused: boolean; focusedPaneOnly: boolean; + explorerPaneId?: string | null; + explorerVisible?: boolean; }): string[] { const nextAgentIds = selectVisibleAgentIds(input); const stableAgentIds = useRef([]); diff --git a/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx b/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx index f1806ede34..4daeb96cb1 100644 --- a/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx +++ b/packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx @@ -858,7 +858,6 @@ function TabChip({ testID={`workspace-tab-${testIdentity}`} triggerRef={dragHandleProps?.setActivatorNodeRef as unknown as undefined} style={tabChipStyle} - onPressIn={isWeb ? handleNavigateTab : undefined} onPress={handleNavigateTab} accessibilityRole="button" accessibilityLabel={accessibilityLabel} diff --git a/packages/app/src/screens/workspace/workspace-explorer-toggle.tsx b/packages/app/src/screens/workspace/workspace-explorer-toggle.tsx index 5e8c3eea78..55a36f9779 100644 --- a/packages/app/src/screens/workspace/workspace-explorer-toggle.tsx +++ b/packages/app/src/screens/workspace/workspace-explorer-toggle.tsx @@ -92,6 +92,6 @@ export function WorkspaceExplorerSidebarToggle({ owner, ...toggleProps }: DesktopWorkspaceExplorerToggleProps) { - if (owner !== "window") return null; + if (owner === "header") return null; return ; } diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx index edd28a3af9..530c1a07d0 100644 --- a/packages/app/src/screens/workspace/workspace-screen.tsx +++ b/packages/app/src/screens/workspace/workspace-screen.tsx @@ -5,6 +5,11 @@ import { type InlinePathTarget, } from "@/assistant-file-links"; import { useFileExplorerActions } from "@/hooks/use-file-explorer-actions"; +import { revealWorkspaceTab } from "@/workspace-tabs/navigation"; +import type { LayoutChangeEvent } from "react-native"; +import { ExplorerSidebarDock } from "@/screens/workspace/explorer-sidebar"; +import { ExplorerFrame } from "./explorer-sidebar/frame"; +import { WorkspaceTabDragScope } from "@/components/workspace-tab-drag-scope"; import { WorkspaceComposerEditingSessionsProvider, useComposerTabFullscreen, @@ -25,7 +30,7 @@ import { type ReactNode, } from "react"; import { useStoreWithEqualityFn } from "zustand/traditional"; -import { useIsFocused } from "@react-navigation/native"; +import { useIsFocused } from "expo-router/react-navigation"; import { BackHandler, Text, View } from "react-native"; import { useQueryClient } from "@tanstack/react-query"; import { useRouter, type Href } from "expo-router"; @@ -73,7 +78,6 @@ import { openWorkspaceTargetBeside, } from "@/workspace-tabs/open-beside"; import { openWorkspacePullRequest } from "@/workspace-tabs/open-supporting-view"; -import { type ExplorerCheckoutContext } from "@/stores/explorer-checkout-context"; import { traceInstant } from "@/performance/native-trace"; import { useSessionStore, type WorkspaceDescriptor } from "@/stores/session-store"; import { @@ -215,7 +219,7 @@ import { } from "@/workspace/file-open"; import { RenderProfile } from "@/utils/render-profiler"; import { useWorkspaceCheckoutStatus } from "@/screens/workspace/use-workspace-checkout-status"; -import { useHasPullRequest, usePullRequestAutoAdd } from "@/panels/pull-request"; +import { useWorkspacePullRequestDiscovery } from "@/panels/pull-request"; const NO_SHEETS: readonly SheetTab[] = []; const WORKSPACE_FLOATING_PANEL_PORTAL_HOST_PREFIX = "workspace-floating-panels"; @@ -772,12 +776,14 @@ function WorkspaceContentProviders({ ); } -function WorkspacePanelProviders({ +function WorkspacePanelSurface({ launcher, children, tabIds, workspaceKey, + onLayout, }: { + onLayout: (event: LayoutChangeEvent) => void; workspaceKey: string; launcher: NewTabLauncher; children: ReactNode; @@ -785,7 +791,13 @@ function WorkspacePanelProviders({ }) { return ( - {children} + + + + {children} + + + ); } @@ -874,14 +886,6 @@ function paneLocalPlacement(paneId: string | null | undefined): WorkspaceTabPlac return paneId ? { mode: "pane", paneId } : FOCUSED_PANE_PLACEMENT; } -function canDetectPullRequest( - isRouteFocused: boolean, - isGitCheckout: boolean, - isCompact: boolean, -): boolean { - return isRouteFocused && isGitCheckout && !isCompact && supportsDesktopPaneSplits(); -} - interface WorkspaceTerminalTabActionsInput { persistenceKey: string | null; openWorkspaceTabFocused: ( @@ -1017,6 +1021,8 @@ function WorkspaceScreenContent({ const _insets = useSafeAreaInsets(); const toast = useToast(); const isMobile = useIsCompactFormFactor(); + const canRenderDesktopPaneSplits = supportsDesktopPaneSplits(); + const layoutMode = useWorkspaceLayoutStore((state) => state.layoutMode); const hasMacTrafficLights = useHasWindowChromeObstruction("top-left"); const explorerToggleOwner = resolveWorkspaceExplorerToggleOwner({ isMobile, @@ -1249,35 +1255,22 @@ function WorkspaceScreenContent({ workspace: workspaceDescriptor, checkoutState: workspaceHeaderCheckoutState, }); - const canDetectPullRequestTab = canDetectPullRequest(isRouteFocused, isGitCheckout, isMobile); - const hasPullRequest = useHasPullRequest({ - serverId: normalizedServerId, - cwd: workspaceDirectory, - enabled: canDetectPullRequestTab, - }); - usePullRequestAutoAdd({ - workspaceKey: persistenceKey, - hasPullRequest, - enabled: canDetectPullRequestTab, - }); - const showMobileAgent = usePanelStore((state) => state.showMobileAgent); - const activeExplorerCheckout = useMemo(() => { - if (!normalizedServerId || !workspaceDirectory) { - return null; - } - return { - serverId: normalizedServerId, - cwd: workspaceDirectory, - isGit: isGitCheckout, - }; - }, [isGitCheckout, normalizedServerId, workspaceDirectory]); - const isExplorerSidebarShowing = useIsExplorerSidebarOpen({ isCompact: isMobile, workspaceKey: persistenceKey, }); + const hasPullRequest = useWorkspacePullRequestDiscovery({ + workspaceKey: persistenceKey, + serverId: normalizedServerId, + cwd: workspaceDirectory, + workspaceActive: isRouteFocused, + isGit: isGitCheckout, + layoutMode, + explorerOpen: isExplorerSidebarShowing, + }); + const explorerSidebarToggleAccessibilityState = useMemo( () => ({ expanded: isExplorerSidebarShowing }), [isExplorerSidebarShowing], @@ -1347,7 +1340,6 @@ function WorkspaceScreenContent({ ); const openInSidePane = useSettings((settings) => settings.openInSidePane); const pullRequestOpenLocation = useSettings((settings) => settings.pullRequestOpenLocation); - const focusWorkspaceTab = useWorkspaceLayoutStore((state) => state.focusTab); const selectWorkspaceTabInPane = useWorkspaceLayoutStore((state) => state.selectTabInPane); const closeWorkspaceTab = useWorkspaceLayoutStore((state) => state.closeTab); const sheets = useWorkspaceLayoutStore((state) => @@ -1369,9 +1361,8 @@ function WorkspaceScreenContent({ toggleExplorerSidebar({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, }); - }, [activeExplorerCheckout, isMobile, persistenceKey]); + }, [isMobile, persistenceKey]); const paneFocusSuppressedRef = useRef(false); const resizeWorkspaceSplit = useWorkspaceLayoutStore((state) => state.resizeSplit); const reorderWorkspaceTabsInPane = useWorkspaceLayoutStore((state) => state.reorderTabsInPane); @@ -1432,6 +1423,8 @@ function WorkspaceScreenContent({ sheetTab, routeFocused: isRouteFocused, focusedPaneOnly: syncFocusedPaneOnly, + explorerPaneId: explorerSidebarPaneId, + explorerVisible: isExplorerSidebarShowing, }); useEffect(() => { for (const agentId of visibleAgentIds) { @@ -1591,9 +1584,9 @@ function WorkspaceScreenContent({ if (!tabId || !persistenceKey) { return; } - focusWorkspaceTab(persistenceKey, tabId); + revealWorkspaceTab(persistenceKey, tabId); }, - [focusWorkspaceTab, persistenceKey], + [persistenceKey], ); const selectTabInPane = useCallback( (paneId: string, tabId: string) => { @@ -1707,9 +1700,6 @@ function WorkspaceScreenContent({ if (!location) { return; } - if (isMobile) { - showMobileAgent(); - } if (!persistenceKey) { return; } @@ -1723,17 +1713,9 @@ function WorkspaceScreenContent({ }); if (tabId) { requestFileNavigation(tabId); - navigateToTabId(tabId); } }, - [ - isMobile, - navigateToTabId, - openInSidePane, - persistenceKey, - requestFileNavigation, - showMobileAgent, - ], + [openInSidePane, persistenceKey, requestFileNavigation], ); const handleOpenWorkspaceFileFromPane = useStableEvent(function handleOpenWorkspaceFileFromPane({ @@ -1760,7 +1742,6 @@ function WorkspaceScreenContent({ }); if (tabId) { requestFileNavigation(tabId); - navigateToTabId(tabId); } return; } @@ -2475,7 +2456,6 @@ function WorkspaceScreenContent({ openExplorerSidebarView({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, view: action.target === "files" ? "files" : "changes", }); return true; @@ -2484,7 +2464,6 @@ function WorkspaceScreenContent({ openWorkspacePullRequest({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, destination: pullRequestOpenLocation, }); return true; @@ -2508,7 +2487,6 @@ function WorkspaceScreenContent({ return true; }, [ - activeExplorerCheckout, focusedPaneTabState.pane?.id, isMobile, openWorkspaceTabFocused, @@ -2649,7 +2627,6 @@ function WorkspaceScreenContent({ openExplorerSidebarView({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, view: "changes", }); } @@ -2659,7 +2636,6 @@ function WorkspaceScreenContent({ openExplorerSidebarView({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, view: "files", }); } @@ -2670,7 +2646,6 @@ function WorkspaceScreenContent({ }, [ focusedPaneTabState.pane?.id, - activeExplorerCheckout, handleCreateBrowserTab, handleCreateDraftTab, isGitCheckout, @@ -2947,7 +2922,6 @@ function WorkspaceScreenContent({ }), [activeFileLineEnd, activeFileLineStart, activeFilePath], ); - const canRenderDesktopPaneSplits = supportsDesktopPaneSplits(); const shouldRenderDesktopPaneFallback = useMemo( () => !isMobile && !canRenderDesktopPaneSplits, [isMobile, canRenderDesktopPaneSplits], @@ -2971,11 +2945,7 @@ function WorkspaceScreenContent({ normalizedWorkspaceId, host: input.host ?? - (canRenderDesktopPaneSplits && - input.paneId !== null && - input.paneId === explorerSidebarPaneId - ? "explorer" - : "main"), + (input.paneId !== null && input.paneId === explorerSidebarPaneId ? "explorer" : "main"), fileNavigationRevision: fileNavigationRevisionByTabId[input.tab.tabId] ?? 0, onOpenTab: (target) => { if (!persistenceKey) { @@ -3004,7 +2974,6 @@ function WorkspaceScreenContent({ preferences: openInSidePane, }); if (tabId && target.kind === "file") requestFileNavigation(tabId); - if (tabId) navigateToTabId(tabId); }, onOpenTargetToSide: canRenderDesktopPaneSplits && @@ -3018,7 +2987,6 @@ function WorkspaceScreenContent({ parentTabId: input.tab.tabId, }); if (tabId && target.kind === "file") requestFileNavigation(tabId); - if (tabId) navigateToTabId(tabId); } : undefined, onCloseCurrentTab: () => { @@ -3502,7 +3470,6 @@ function WorkspaceScreenContent({ - - - {(topOverlayInset) => ( - - {content} - - )} - - - - + + + {(topOverlayInset) => ( + + {content} + + )} + + + ) : ( {rendersDesktopSplitContent ? null : renderWorkspaceScreenHeader()} @@ -3646,17 +3605,91 @@ function WorkspaceScreenContent({ ) : null} - - {desktopContent} - + {desktopContent} ); + const [workspaceViewportWidth, setWorkspaceViewportWidth] = useState(0); + const measureWorkspaceWidth = useCallback( + (event: LayoutChangeEvent) => setWorkspaceViewportWidth(event.nativeEvent.layout.width), + [], + ); + const sharedExplorer = useMemo(() => { + if (!workspaceLayout || !explorerSidebarPaneId || !persistenceKey) return null; + const explorerPane = findPaneById(workspaceLayout.root, explorerSidebarPaneId); + if (!explorerPane) return null; + const dock = ( + + ); + return ( + + {dock} + + ); + }, [ + workspaceLayout, + explorerSidebarPaneId, + persistenceKey, + isMobile, + uiTabs, + normalizedServerId, + normalizedWorkspaceId, + isRouteFocused, + isExplorerSidebarShowing, + closingTabIds, + hoveredCloseTabKey, + selectTabInPane, + handleCloseTabById, + handleCreateNewTab, + handleCopyResumeCommand, + handleCopyAgentId, + handleCopyTerminalId, + handleCopyFilePath, + handleReloadAgent, + handleRenameTab, + handleCloseTabsToLeftInPane, + handleCloseTabsToRightInPane, + handleCloseOtherTabsInPane, + toggleFocusMode, + handleReorderTabsInPane, + buildDesktopPaneContentModel, + renderExplorerSidebarHeaderAction, + workspaceViewportWidth, + desktopFocusModeEnabled, + ]); + const { revealDirectory } = useFileExplorerActions({ serverId: normalizedServerId, workspaceId: normalizedWorkspaceId, @@ -3670,7 +3703,6 @@ function WorkspaceScreenContent({ openExplorerSidebarView({ isCompact: isMobile, workspaceKey: persistenceKey, - checkout: activeExplorerCheckout, view: "files", }); }); @@ -3703,12 +3735,30 @@ function WorkspaceScreenContent({ workspaceId={normalizedWorkspaceId} isRouteFocused={isRouteFocused} /> - + - {workspaceCenterColumn} + + {workspaceCenterColumn} + {sharedExplorer} + - + ({ backgroundColor: theme.colors.surfaceWorkspace, }, threePaneRow: { + // Keep the Explorer overlay below the workspace sheet host on web as well as native. + zIndex: 0, flex: 1, minHeight: 0, flexDirection: "row", @@ -3951,7 +4003,7 @@ const styles = StyleSheet.create((theme) => ({ position: "relative", }, mobileMountedTabSlot: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, }, contentPlaceholder: { flex: 1, diff --git a/packages/app/src/screens/workspace/workspace-tab-layout.test.ts b/packages/app/src/screens/workspace/workspace-tab-layout.test.ts index b2b226e645..14e7b89b31 100644 --- a/packages/app/src/screens/workspace/workspace-tab-layout.test.ts +++ b/packages/app/src/screens/workspace/workspace-tab-layout.test.ts @@ -1,3 +1,7 @@ +import { + WorkspaceHeaderExplorerToggle, + WorkspaceExplorerSidebarToggle, +} from "./workspace-explorer-toggle"; import { describe, expect, it } from "vitest"; import { computeWorkspaceTabLayout, @@ -144,3 +148,25 @@ describe("retainWorkspaceTabMeasuredWidth", () => { expect(retainWorkspaceTabMeasuredWidth(720, 640)).toBe(640); }); }); + +describe("Explorer toggle ownership", () => { + const toggleProps = { + onPress: () => {}, + label: "Close Explorer sidebar", + tooltipLabel: "Toggle Explorer sidebar", + tooltipKeys: [], + accessibilityState: { expanded: true }, + }; + + it("keeps only the header toggle when window controls do not obstruct it", () => { + expect(WorkspaceHeaderExplorerToggle({ ...toggleProps, owner: "header" })).not.toBeNull(); + expect(WorkspaceExplorerSidebarToggle({ ...toggleProps, owner: "header" })).toBeNull(); + }); + + it("keeps the dock toggle for window-owned and compact overlay chrome", () => { + for (const owner of ["window", "mobile"] as const) { + expect(WorkspaceHeaderExplorerToggle({ ...toggleProps, owner })).toBeNull(); + expect(WorkspaceExplorerSidebarToggle({ ...toggleProps, owner })).not.toBeNull(); + } + }); +}); diff --git a/packages/app/src/stores/explorer-checkout-context.ts b/packages/app/src/stores/explorer-checkout-context.ts deleted file mode 100644 index 926c02d4e0..0000000000 --- a/packages/app/src/stores/explorer-checkout-context.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface ExplorerCheckoutContext { - serverId: string; - cwd: string; - isGit: boolean; -} diff --git a/packages/app/src/stores/explorer-tab-memory.ts b/packages/app/src/stores/explorer-tab-memory.ts deleted file mode 100644 index 3e26c0e947..0000000000 --- a/packages/app/src/stores/explorer-tab-memory.ts +++ /dev/null @@ -1,34 +0,0 @@ -export type ExplorerTab = "changes" | "files" | "pr"; - -export function isExplorerTab(value: unknown): value is ExplorerTab { - return value === "changes" || value === "files" || value === "pr"; -} - -export function buildExplorerCheckoutKey(serverId: string, cwd: string): string | null { - const trimmedServerId = serverId.trim(); - const trimmedCwd = cwd.trim(); - if (!trimmedServerId || !trimmedCwd) { - return null; - } - return `${trimmedServerId}::${trimmedCwd}`; -} - -export function coerceExplorerTabForCheckout(tab: ExplorerTab, isGit: boolean): ExplorerTab { - if (!isGit && tab === "changes") { - return "files"; - } - return tab; -} - -export function resolveExplorerTabForCheckout(params: { - serverId: string; - cwd: string; - isGit: boolean; - explorerTabByCheckout: Record; -}): ExplorerTab { - const key = buildExplorerCheckoutKey(params.serverId, params.cwd); - const stored = key ? params.explorerTabByCheckout[key] : null; - const defaultTab: ExplorerTab = params.isGit ? "changes" : "files"; - const nextTab = stored && isExplorerTab(stored) ? stored : defaultTab; - return coerceExplorerTabForCheckout(nextTab, params.isGit); -} diff --git a/packages/app/src/stores/panel-store/index.ts b/packages/app/src/stores/panel-store/index.ts index 0fa86399d9..8af964f181 100644 --- a/packages/app/src/stores/panel-store/index.ts +++ b/packages/app/src/stores/panel-store/index.ts @@ -2,15 +2,6 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { - buildExplorerCheckoutKey, - coerceExplorerTabForCheckout, - resolveExplorerTabForCheckout, - type ExplorerTab, -} from "../explorer-tab-memory"; -import { type ExplorerCheckoutContext } from "../explorer-checkout-context"; -import { - buildOpenFileExplorerPatch, - buildToggleFileExplorerPatch, clampTreeRailWidth, clampSidebarWidth, DEFAULT_TREE_RAIL_WIDTH, @@ -32,8 +23,6 @@ import { } from "./state"; import { isWeb } from "@/constants/platform"; import { createValidatedPersistStorage } from "@/storage/validated-persist-storage"; -export type { ExplorerTab } from "../explorer-tab-memory"; -export type { ExplorerCheckoutContext } from "../explorer-checkout-context"; export type { DesktopSidebarState, MobilePanelView, @@ -63,8 +52,6 @@ export interface PanelState { desktop: DesktopSidebarState; // File explorer settings (shared between mobile/desktop) - explorerTab: ExplorerTab; - explorerTabByCheckout: Record; expandedPathsByWorkspace: Record; // Changes-view folder tree. Inverted semantics vs the fields above: // this stores COLLAPSED directory paths (empty = all folders expanded), keyed @@ -85,6 +72,7 @@ export interface PanelState { exitFocusMode: () => void; showMobileAgent: () => void; showMobileAgentList: () => void; + showMobileFileExplorer: () => void; toggleMobileAgentList: () => void; openDesktopAgentList: () => void; closeDesktopAgentList: () => void; @@ -92,16 +80,11 @@ export interface PanelState { openAgentListForLayout: (input: PanelLayoutInput) => void; closeAgentListForLayout: (input: PanelLayoutInput) => void; toggleAgentListForLayout: (input: PanelLayoutInput) => void; - openCompactFileExplorer: (checkout: ExplorerCheckoutContext) => void; - toggleCompactFileExplorer: (checkout: ExplorerCheckoutContext) => void; // File explorer settings actions - setExplorerTab: (tab: ExplorerTab) => void; - setExplorerTabForCheckout: (params: ExplorerCheckoutContext & { tab: ExplorerTab }) => void; setExpandedPathsForWorkspace: (workspaceKey: string, paths: ExpandedPathsUpdate) => void; setDiffCollapsedFoldersForWorkspace: (workspaceKey: string, dirPaths: string[]) => void; setCollapsedFilePathsForWorkspace: (workspaceKey: string, paths: string[]) => void; - activateExplorerTabForCheckout: (checkout: ExplorerCheckoutContext) => void; setSidebarWidth: (width: number) => void; setExplorerSortOption: (option: SortOption) => void; toggleExplorerShowHiddenFiles: () => void; @@ -132,8 +115,6 @@ export const usePanelStore = create()( }, // File explorer defaults - explorerTab: "changes", - explorerTabByCheckout: {}, expandedPathsByWorkspace: {}, diffCollapsedFoldersByWorkspace: {}, collapsedFilePathsByWorkspace: {}, @@ -158,6 +139,8 @@ export const usePanelStore = create()( showMobileAgent: () => set((state) => setMobilePanelTargetPatch(state, "agent")), showMobileAgentList: () => set((state) => setMobilePanelTargetPatch(state, "agent-list")), + showMobileFileExplorer: () => + set((state) => setMobilePanelTargetPatch(state, "file-explorer")), toggleMobileAgentList: () => set((state) => @@ -221,29 +204,6 @@ export const usePanelStore = create()( }; }), - openCompactFileExplorer: (checkout) => - set((state) => buildOpenFileExplorerPatch(state, checkout)), - - toggleCompactFileExplorer: (checkout) => - set((state) => buildToggleFileExplorerPatch(state, checkout)), - - setExplorerTab: (tab) => set({ explorerTab: tab }), - setExplorerTabForCheckout: ({ serverId, cwd, isGit, tab }) => - set((state) => { - const resolvedTab = coerceExplorerTabForCheckout(tab, isGit); - const key = buildExplorerCheckoutKey(serverId, cwd); - const nextState: Partial = { explorerTab: resolvedTab }; - if (key) { - const current = state.explorerTabByCheckout[key]; - if (current !== resolvedTab) { - nextState.explorerTabByCheckout = { - ...state.explorerTabByCheckout, - [key]: resolvedTab, - }; - } - } - return nextState; - }), setExpandedPathsForWorkspace: (workspaceKey, paths) => set((state) => { const currentPaths = state.expandedPathsByWorkspace[workspaceKey] ?? ["."]; @@ -269,15 +229,6 @@ export const usePanelStore = create()( [workspaceKey]: paths, }, })), - activateExplorerTabForCheckout: (checkout) => - set((state) => ({ - explorerTab: resolveExplorerTabForCheckout({ - serverId: checkout.serverId, - cwd: checkout.cwd, - isGit: checkout.isGit, - explorerTabByCheckout: state.explorerTabByCheckout, - }), - })), setSidebarWidth: (width) => set({ sidebarWidth: clampSidebarWidth(width) }), setExplorerSortOption: (option) => set({ explorerSortOption: option }), toggleExplorerShowHiddenFiles: () => @@ -287,13 +238,11 @@ export const usePanelStore = create()( }), { name: "panel-state", - version: 16, + version: 17, storage: createValidatedPersistStorage(AsyncStorage, PanelPersistedStateSchema), migrate: (persistedState, version) => migratePanelState(persistedState, version), partialize: (state) => ({ desktop: state.desktop, - explorerTab: state.explorerTab, - explorerTabByCheckout: state.explorerTabByCheckout, expandedPathsByWorkspace: state.expandedPathsByWorkspace, diffCollapsedFoldersByWorkspace: state.diffCollapsedFoldersByWorkspace, collapsedFilePathsByWorkspace: state.collapsedFilePathsByWorkspace, diff --git a/packages/app/src/stores/panel-store/state.test.ts b/packages/app/src/stores/panel-store/state.test.ts index 19c8d7d17a..ad52b8a8c4 100644 --- a/packages/app/src/stores/panel-store/state.test.ts +++ b/packages/app/src/stores/panel-store/state.test.ts @@ -1,12 +1,5 @@ import { describe, expect, it } from "vitest"; import { - buildExplorerCheckoutKey, - resolveExplorerTabForCheckout, - type ExplorerTab, -} from "@/stores/explorer-tab-memory"; -import { - buildOpenFileExplorerPatch, - buildToggleFileExplorerPatch, DEFAULT_TREE_RAIL_WIDTH, migratePanelState, selectIsAgentListOpen, @@ -22,81 +15,10 @@ function makePanelState(overrides: Partial = {}): PanelCoreState agentListOpen: false, focusModeEnabled: false, }, - explorerTab: "changes", - explorerTabByCheckout: {}, ...overrides, }; } -describe("panel-store explorer tab resolution", () => { - const serverId = "server-1"; - const cwd = "/tmp/repo"; - - it("defaults to changes for git checkouts", () => { - expect( - resolveExplorerTabForCheckout({ - serverId, - cwd, - isGit: true, - explorerTabByCheckout: {}, - }), - ).toBe("changes"); - }); - - it("defaults to files for non-git checkouts", () => { - expect( - resolveExplorerTabForCheckout({ - serverId, - cwd, - isGit: false, - explorerTabByCheckout: {}, - }), - ).toBe("files"); - }); - - it("restores a stored files tab for git checkouts", () => { - const key = buildExplorerCheckoutKey(serverId, cwd)!; - expect( - resolveExplorerTabForCheckout({ - serverId, - cwd, - isGit: true, - explorerTabByCheckout: { - [key]: "files", - }, - }), - ).toBe("files"); - }); - - it("falls back to default when stored tab is invalid", () => { - const key = buildExplorerCheckoutKey(serverId, cwd)!; - expect( - resolveExplorerTabForCheckout({ - serverId, - cwd, - isGit: true, - explorerTabByCheckout: { - [key]: "terminals" as unknown as ExplorerTab, - }, - }), - ).toBe("changes"); - }); - - it("coerces stored changes to files for non-git checkouts", () => { - const key = buildExplorerCheckoutKey(serverId, cwd)!; - expect( - resolveExplorerTabForCheckout({ - serverId, - cwd, - isGit: false, - explorerTabByCheckout: { - [key]: "changes", - }, - }), - ).toBe("files"); - }); -}); - describe("panel-store migration", () => { it("defaults hidden-file visibility to showing hidden files", () => { const state = migratePanelState({}, 10); @@ -191,57 +113,12 @@ describe("panel-store visibility selectors", () => { }); }); -describe("panel-store compact file explorer actions", () => { - it("opens the compact explorer and resolves the tab from the explicit checkout", () => { - const checkout = { serverId: "server-1", cwd: "/tmp/repo", isGit: true }; - const key = buildExplorerCheckoutKey(checkout.serverId, checkout.cwd)!; - const state = makePanelState({ - explorerTab: "changes", - explorerTabByCheckout: { [key]: "files" }, - }); - - const patch = buildOpenFileExplorerPatch(state, checkout); - - expect(patch.mobilePanel).toEqual({ target: "file-explorer", revision: 1 }); - expect(patch.explorerTab).toBe("files"); - }); - - it("toggles the explorer closed without changing the active tab", () => { - const state = makePanelState({ - mobilePanel: { target: "file-explorer", revision: 1 }, - explorerTab: "files", - }); - - const patch = buildToggleFileExplorerPatch(state, { - serverId: "server-1", - cwd: "/tmp/repo", - isGit: true, - }); - - expect(patch).toEqual({ mobilePanel: { target: "agent", revision: 2 } }); - }); - - it("coerces changes to files for a non-git checkout", () => { - const checkout = { serverId: "server-1", cwd: "/tmp/repo", isGit: false }; - const key = buildExplorerCheckoutKey(checkout.serverId, checkout.cwd)!; - const state = makePanelState({ - explorerTab: "changes", - explorerTabByCheckout: { [key]: "changes" }, - }); - - expect(buildOpenFileExplorerPatch(state, checkout).explorerTab).toBe("files"); - }); - - it("opens with the default files tab for an explicit non-git checkout with no stored tab", () => { - const state = makePanelState({ explorerTab: "changes", explorerTabByCheckout: {} }); - - const patch = buildOpenFileExplorerPatch(state, { - serverId: "server-1", - cwd: "/tmp/non-git", - isGit: false, - }); - - expect(patch.mobilePanel).toEqual({ target: "file-explorer", revision: 1 }); - expect(patch.explorerTab).toBe("files"); - }); +it("discards obsolete checkout selection while preserving other panel preferences", () => { + const state = migratePanelState( + { explorerTab: "files", explorerTabByCheckout: { checkout: "changes" }, sidebarWidth: 400 }, + 16, + ); + expect(state).not.toHaveProperty("explorerTab"); + expect(state).not.toHaveProperty("explorerTabByCheckout"); + expect(state.sidebarWidth).toBe(400); }); diff --git a/packages/app/src/stores/panel-store/state.ts b/packages/app/src/stores/panel-store/state.ts index c9b68d2584..cbbead4161 100644 --- a/packages/app/src/stores/panel-store/state.ts +++ b/packages/app/src/stores/panel-store/state.ts @@ -1,10 +1,3 @@ -import { - buildExplorerCheckoutKey, - isExplorerTab, - resolveExplorerTabForCheckout, - type ExplorerTab, -} from "../explorer-tab-memory"; -import { type ExplorerCheckoutContext } from "../explorer-checkout-context"; import { z } from "zod"; export type MobilePanelView = "agent" | "agent-list" | "file-explorer"; @@ -36,8 +29,6 @@ export interface PanelLayoutInput { export interface PanelCoreState { mobilePanel: MobilePanelSelection; desktop: DesktopSidebarState; - explorerTab: ExplorerTab; - explorerTabByCheckout: Record; } function clampNumber(value: number, min: number, max: number): number { @@ -77,45 +68,6 @@ export function setMobilePanelTarget( return { target, revision: selection.revision + 1 }; } -function resolveExplorerTabFromCheckout( - state: PanelCoreState, - checkout: ExplorerCheckoutContext, -): ExplorerTab { - return resolveExplorerTabForCheckout({ - serverId: checkout.serverId, - cwd: checkout.cwd, - isGit: checkout.isGit, - explorerTabByCheckout: state.explorerTabByCheckout, - }); -} - -export interface OpenFileExplorerPatch { - mobilePanel: MobilePanelSelection; - explorerTab: ExplorerTab; -} - -export function buildOpenFileExplorerPatch( - state: PanelCoreState, - checkout: ExplorerCheckoutContext, -): OpenFileExplorerPatch { - return { - mobilePanel: setMobilePanelTarget(state.mobilePanel, "file-explorer"), - explorerTab: resolveExplorerTabFromCheckout(state, checkout), - }; -} - -export type ToggleFileExplorerPatch = OpenFileExplorerPatch | { mobilePanel: MobilePanelSelection }; - -export function buildToggleFileExplorerPatch( - state: PanelCoreState, - checkout: ExplorerCheckoutContext, -): ToggleFileExplorerPatch { - if (!selectIsCompactFileExplorerOpen(state)) { - return buildOpenFileExplorerPatch(state, checkout); - } - return { mobilePanel: setMobilePanelTarget(state.mobilePanel, "agent") }; -} - const ExplorerTabSchema = z.enum(["changes", "files", "pr"]); const DesktopSidebarStorageSchema = z.strictObject({ agentListOpen: z.boolean().optional(), @@ -156,26 +108,6 @@ export const PanelPersistedStateSchema = z.strictObject({ type MigratablePanelState = z.infer; -function migratePanelExplorerTabByCheckout(state: MigratablePanelState, version: number): void { - if ( - version < 4 || - typeof state.explorerTabByCheckout !== "object" || - !state.explorerTabByCheckout - ) { - state.explorerTabByCheckout = {}; - return; - } - const entries = Object.entries(state.explorerTabByCheckout); - const next: Record = {}; - for (const [key, value] of entries) { - if (!isExplorerTab(value)) { - continue; - } - next[key] = value; - } - state.explorerTabByCheckout = next; -} - function migratePanelDesktopFocusMode(state: MigratablePanelState): void { const desktop = state.desktop; if (!desktop) { @@ -216,10 +148,8 @@ export function migratePanelState(persistedState: unknown, version: number): Mig if (state.desktop) { delete state.desktop.fileExplorerOpen; } - if (!isExplorerTab(state.explorerTab)) { - state.explorerTab = "changes"; - } - migratePanelExplorerTabByCheckout(state, version); + delete state.explorerTab; + delete state.explorerTabByCheckout; if (version < 8) { migratePanelDesktopFocusMode(state); } @@ -263,6 +193,3 @@ export function migratePanelState(persistedState: unknown, version: number): Mig return state; } - -export { buildExplorerCheckoutKey, resolveExplorerTabForCheckout }; -export type { ExplorerTab, ExplorerCheckoutContext }; diff --git a/packages/app/src/stores/workspace-layout-store.test.ts b/packages/app/src/stores/workspace-layout-store.test.ts index 5f170bed7e..a989dc0dd3 100644 --- a/packages/app/src/stores/workspace-layout-store.test.ts +++ b/packages/app/src/stores/workspace-layout-store.test.ts @@ -5096,6 +5096,21 @@ describe("compact workspace sheet", () => { expect(tabKinds(store)).toEqual(["terminal", "terminal"]); }); + it("honors an explicit Explorer pane destination on compact layouts", () => { + const store = createCompactStore(); + const paneId = store.getState().showExplorerSidebar(workspaceKey)!; + const tabId = store.getState().openTab({ + workspaceKey, + target: fileTarget, + intent: "new", + placement: { mode: "pane", paneId }, + }); + expect(topSheet(store)).toBeUndefined(); + expect( + findPaneById(store.getState().layoutByWorkspace[workspaceKey].root, paneId)?.focusedTabId, + ).toBe(tabId); + }); + it("keeps a chat shown in the sheet open for timeline sync until the sheet closes", () => { const store = createCompactStore(); seedAgents([ diff --git a/packages/app/src/stores/workspace-layout-store.ts b/packages/app/src/stores/workspace-layout-store.ts index 4bf86ae093..01c932605e 100644 --- a/packages/app/src/stores/workspace-layout-store.ts +++ b/packages/app/src/stores/workspace-layout-store.ts @@ -123,6 +123,10 @@ export interface SheetTab { parentTabId: string | null; } +export type WorkspaceTabDestination = + | { kind: "pane"; paneId: string; host: "main" | "explorer"; tabId: string } + | { kind: "sheet"; tabId: string }; + interface WorkspaceLayoutStore { /** Published once by the app shell; callers never pass a form factor to open a tab. */ layoutMode: WorkspaceLayoutMode; @@ -161,11 +165,13 @@ interface WorkspaceLayoutStore { resolvePlacement: () => Pick, ) => string | null; /** Reveals the Explorer sidebar without selecting a view. Returns its pane id. */ + ensureExplorerSidebar: (workspaceKey: string) => string | null; showExplorerSidebar: (workspaceKey: string) => string | null; hideExplorerSidebar: (workspaceKey: string) => void; /** Returns the ordinary right-side workspace pane, creating it when absent. */ ensureSidePane: (workspaceKey: string, options?: { focus: boolean }) => string | null; closeTab: (workspaceKey: string, tabId: string) => void; + getTabDestination: (workspaceKey: string, tabId: string) => WorkspaceTabDestination | null; focusTab: (workspaceKey: string, tabId: string) => void; selectTabInPane: (workspaceKey: string, paneId: string, tabId: string) => void; replaceTab: ( @@ -1036,12 +1042,15 @@ export function createWorkspaceLayoutStore( normalizedWorkspaceKey, input.parentTabId, ); - const sheetPlacement = resolveSheetPlacement( - get(), - normalizedWorkspaceKey, - normalizedTarget, - input.intent, - ); + const sheetPlacement = + input.placement?.mode === "pane" + ? null + : resolveSheetPlacement( + get(), + normalizedWorkspaceKey, + normalizedTarget, + input.intent, + ); if (sheetPlacement) { const sheets = getSheets(get(), normalizedWorkspaceKey); const { keptIndex } = sheetPlacement; @@ -1101,8 +1110,18 @@ export function createWorkspaceLayoutStore( if (!result) { return null; } + const openedLayout = + get().layoutMode === "compact" && placement.explorerSidebarPaneId + ? (setPaneHiddenInLayout({ + layout: result.layout, + paneId: placement.explorerSidebarPaneId, + hidden: + findPaneById(placement.layout.root, placement.explorerSidebarPaneId)?.hidden === + true, + }) ?? result.layout) + : result.layout; const nextLayout = keepWorkspaceFocusOutOfExplorerSidebar( - result.layout, + openedLayout, placement.explorerSidebarPaneId, placement.layout.focusedPaneId, ); @@ -1175,7 +1194,7 @@ export function createWorkspaceLayoutStore( set(promoted.patch); return promoted.tabId; }, - showExplorerSidebar: (workspaceKey) => { + ensureExplorerSidebar: (workspaceKey) => { const normalizedWorkspaceKey = trimNonEmpty(workspaceKey); if (!normalizedWorkspaceKey) { return null; @@ -1196,14 +1215,11 @@ export function createWorkspaceLayoutStore( state.layoutByWorkspace, normalizedWorkspaceKey, ); - const revealedLayout = - setPaneHiddenInLayout({ layout: currentLayout, paneId, hidden: false }) ?? - currentLayout; return { layoutByWorkspace: { ...state.layoutByWorkspace, [normalizedWorkspaceKey]: keepWorkspaceFocusOutOfExplorerSidebar( - revealedLayout, + currentLayout, paneId, currentLayout.focusedPaneId, ), @@ -1216,6 +1232,18 @@ export function createWorkspaceLayoutStore( }); return paneId; }, + showExplorerSidebar: (workspaceKey) => { + const paneId = get().ensureExplorerSidebar(workspaceKey); + if (!paneId || get().layoutMode === "compact") return paneId; + set((state) => { + const layout = state.layoutByWorkspace[workspaceKey]; + const next = setPaneHiddenInLayout({ layout, paneId, hidden: false }); + return next + ? { layoutByWorkspace: { ...state.layoutByWorkspace, [workspaceKey]: next } } + : state; + }); + return paneId; + }, hideExplorerSidebar: (workspaceKey) => { const normalizedWorkspaceKey = trimNonEmpty(workspaceKey); if (!normalizedWorkspaceKey) { @@ -1367,6 +1395,26 @@ export function createWorkspaceLayoutStore( }; }); }, + getTabDestination: (workspaceKey, tabId) => { + const state = get(); + if (state.sheetsByWorkspace[workspaceKey]?.some((sheet) => sheet.tab.tabId === tabId)) { + return { kind: "sheet", tabId }; + } + const layout = state.layoutByWorkspace[workspaceKey]; + if (!layout) return null; + const pane = findPaneContainingTab(layout.root, tabId); + if (!pane) return null; + const explorerId = resolveExplorerSidebarPaneId( + layout, + state.explorerSidebarPaneIdByWorkspace[workspaceKey], + ); + return { + kind: "pane", + paneId: pane.id, + host: pane.id === explorerId ? "explorer" : "main", + tabId, + }; + }, focusTab: (workspaceKey, tabId) => { const normalizedWorkspaceKey = trimNonEmpty(workspaceKey); const normalizedTabId = trimNonEmpty(tabId); @@ -1387,7 +1435,7 @@ export function createWorkspaceLayoutStore( setPaneHiddenInLayout({ layout, paneId: explorerSidebarPaneId, - hidden: false, + hidden: state.layoutMode === "compact" ? tabPane.hidden === true : false, }) ?? layout; nextLayout = selectTabInPaneInLayout({ diff --git a/packages/app/src/styles/unistyles.ts b/packages/app/src/styles/unistyles.ts index b679d5e694..407faafdf6 100644 --- a/packages/app/src/styles/unistyles.ts +++ b/packages/app/src/styles/unistyles.ts @@ -6,6 +6,7 @@ StyleSheet.configure({ breakpoints: { xs: 0, sm: 576, + medium: 600, md: 720, lg: 992, xl: 1200, @@ -21,6 +22,7 @@ type AppThemes = typeof REGISTERED_THEMES; interface AppBreakpoints { xs: number; sm: number; + medium: number; md: number; lg: number; xl: number; diff --git a/packages/app/src/usage/window-bar.tsx b/packages/app/src/usage/window-bar.tsx index 9082f2dbac..99c1eb9f21 100644 --- a/packages/app/src/usage/window-bar.tsx +++ b/packages/app/src/usage/window-bar.tsx @@ -196,14 +196,14 @@ const styles = StyleSheet.create((theme) => ({ display: "none", }, highlightPinned: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, zIndex: -1, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.surface2, }, // The pinned surface at half strength: a separate layer, so the text keeps full opacity. highlightHovered: { - ...StyleSheet.absoluteFillObject, + ...StyleSheet.absoluteFill, zIndex: -1, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.surface2, diff --git a/packages/app/src/workspace-tabs/explorer-sidebar.test.ts b/packages/app/src/workspace-tabs/explorer-sidebar.test.ts index af72c48194..15fd44f649 100644 --- a/packages/app/src/workspace-tabs/explorer-sidebar.test.ts +++ b/packages/app/src/workspace-tabs/explorer-sidebar.test.ts @@ -23,7 +23,6 @@ import { } from "@/workspace-tabs/explorer-sidebar"; const WORKSPACE_KEY = "server-1:ws-main"; -const CHECKOUT = { serverId: "server-1", cwd: "/tmp/repo", isGit: true }; beforeEach(() => { useWorkspaceLayoutStore.setState({ @@ -34,40 +33,35 @@ beforeEach(() => { }); usePanelStore.setState({ mobilePanel: { target: "agent", revision: 0 }, - explorerTab: "files", - explorerTabByCheckout: {}, }); }); describe("Explorer sidebar", () => { - it("selects the Explorer shell from layout and split capabilities", () => { + it("selects the Explorer shell from the form factor", () => { expect(resolveExplorerSidebarPresentation({ isCompact: true })).toBe("overlay"); - expect( - resolveExplorerSidebarPresentation({ isCompact: false, supportsPaneSplits: false }), - ).toBe("dock"); - expect(resolveExplorerSidebarPresentation({ isCompact: false, supportsPaneSplits: true })).toBe( - "pane", - ); + expect(resolveExplorerSidebarPresentation({ isCompact: false })).toBe("dock"); }); - it("uses the compact explorer without creating a desktop pane", () => { + it("uses the same Explorer pane inside the compact overlay", () => { openExplorerSidebarView({ isCompact: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, view: "changes", }); expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); - expect(useWorkspaceLayoutStore.getState().layoutByWorkspace[WORKSPACE_KEY]).toBeUndefined(); + const state = useWorkspaceLayoutStore.getState(); + const layout = state.layoutByWorkspace[WORKSPACE_KEY]; + const pane = findPaneById(layout.root, selectExplorerSidebarPaneId(state, WORKSPACE_KEY)!); + expect( + collectAllTabs(layout.root).find((tab) => tab.tabId === pane?.focusedTabId)?.target.kind, + ).toBe("changes_tree"); }); it("creates a dedicated desktop Explorer containing only its requested tree", () => { openExplorerSidebarView({ isCompact: false, - supportsPaneSplits: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, view: "files", }); @@ -81,9 +75,7 @@ describe("Explorer sidebar", () => { it("toggles the desktop Explorer independently of ordinary panes", () => { const input = { isCompact: false, - supportsPaneSplits: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, }; openExplorerSidebarView({ ...input, view: "files" }); toggleExplorerSidebar(input); @@ -104,16 +96,13 @@ describe("Explorer sidebar", () => { }); it("toggles the compact Explorer without changing its selected view", () => { - usePanelStore.getState().setExplorerTabForCheckout({ ...CHECKOUT, tab: "files" }); const input = { isCompact: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, }; toggleExplorerSidebar(input); expect(isExplorerSidebarOpen(input)).toBe(true); - expect(usePanelStore.getState().explorerTab).toBe("files"); }); }); diff --git a/packages/app/src/workspace-tabs/explorer-sidebar.ts b/packages/app/src/workspace-tabs/explorer-sidebar.ts index ab2d7db716..26c64e016b 100644 --- a/packages/app/src/workspace-tabs/explorer-sidebar.ts +++ b/packages/app/src/workspace-tabs/explorer-sidebar.ts @@ -1,6 +1,4 @@ -import { supportsDesktopPaneSplits } from "@/constants/layout"; import { selectIsCompactFileExplorerOpen, usePanelStore } from "@/stores/panel-store"; -import type { ExplorerCheckoutContext } from "@/stores/explorer-checkout-context"; import { selectIsExplorerSidebarVisible, useWorkspaceLayoutStore, @@ -8,7 +6,7 @@ import { import type { WorkspaceTabTarget } from "@/workspace-tabs/model"; export type ExplorerSidebarView = "changes" | "files" | "pr"; -export type ExplorerSidebarPresentation = "overlay" | "dock" | "pane"; +export type ExplorerSidebarPresentation = "overlay" | "dock"; const VIEW_TARGETS: Record = { changes: { kind: "changes_tree" }, @@ -19,48 +17,24 @@ const VIEW_TARGETS: Record = { export interface ExplorerSidebarQuery { isCompact: boolean; workspaceKey: string | null; - supportsPaneSplits?: boolean; -} - -export interface ExplorerSidebarInput extends ExplorerSidebarQuery { - checkout: ExplorerCheckoutContext | null; } export function resolveExplorerSidebarPresentation( - input: Pick, + input: Pick, ): ExplorerSidebarPresentation { if (input.isCompact) { return "overlay"; } - return (input.supportsPaneSplits ?? supportsDesktopPaneSplits()) ? "pane" : "dock"; -} - -export function usesCompactExplorerSidebar( - input: Pick, -): boolean { - return resolveExplorerSidebarPresentation(input) !== "pane"; -} - -function canUseExplorerSidebar( - input: Pick, -): boolean { - return resolveExplorerSidebarPresentation(input) === "pane"; + return "dock"; } /** Reveals the Explorer sidebar and selects one of its navigation trees. */ export function openExplorerSidebarView( - input: ExplorerSidebarInput & { view: ExplorerSidebarView }, + input: ExplorerSidebarQuery & { view: ExplorerSidebarView }, ): void { - if (usesCompactExplorerSidebar(input)) { - if (!input.checkout) return; - const panel = usePanelStore.getState(); - panel.setExplorerTabForCheckout({ ...input.checkout, tab: input.view }); - panel.openCompactFileExplorer(input.checkout); - return; - } if (!input.workspaceKey) return; const store = useWorkspaceLayoutStore.getState(); - const paneId = store.showExplorerSidebar(input.workspaceKey); + const paneId = showExplorerSidebar(input); store.openTab({ workspaceKey: input.workspaceKey, target: VIEW_TARGETS[input.view], @@ -69,29 +43,33 @@ export function openExplorerSidebarView( }); } -export function showExplorerSidebar(input: ExplorerSidebarInput): void { - if (usesCompactExplorerSidebar(input)) { - if (input.checkout) usePanelStore.getState().openCompactFileExplorer(input.checkout); - return; +export function showExplorerSidebar(input: ExplorerSidebarQuery): string | null { + if (input.isCompact) { + usePanelStore.getState().showMobileFileExplorer(); } - if (input.workspaceKey && canUseExplorerSidebar(input)) { - useWorkspaceLayoutStore.getState().showExplorerSidebar(input.workspaceKey); + if (input.workspaceKey) { + const store = useWorkspaceLayoutStore.getState(); + return input.isCompact + ? store.ensureExplorerSidebar(input.workspaceKey) + : store.showExplorerSidebar(input.workspaceKey); } + return null; } -export function hideExplorerSidebar(input: ExplorerSidebarInput): void { - if (usesCompactExplorerSidebar(input)) { +export function hideExplorerSidebar(input: ExplorerSidebarQuery): void { + if (input.isCompact) { usePanelStore.getState().showMobileAgent(); return; } - if (input.workspaceKey && canUseExplorerSidebar(input)) { + if (input.workspaceKey) { useWorkspaceLayoutStore.getState().hideExplorerSidebar(input.workspaceKey); } } -export function toggleExplorerSidebar(input: ExplorerSidebarInput): void { - if (usesCompactExplorerSidebar(input)) { - if (input.checkout) usePanelStore.getState().toggleCompactFileExplorer(input.checkout); +export function toggleExplorerSidebar(input: ExplorerSidebarQuery): void { + if (input.isCompact) { + if (isExplorerSidebarOpen(input)) hideExplorerSidebar(input); + else showExplorerSidebar(input); return; } if (!input.workspaceKey) return; @@ -105,20 +83,17 @@ export function toggleExplorerSidebar(input: ExplorerSidebarInput): void { export function useIsExplorerSidebarOpen(input: ExplorerSidebarQuery): boolean { const compactOpen = usePanelStore(selectIsCompactFileExplorerOpen); const paneOpen = useWorkspaceLayoutStore((state) => - input.workspaceKey && canUseExplorerSidebar(input) - ? selectIsExplorerSidebarVisible(state, input.workspaceKey) - : false, + input.workspaceKey ? selectIsExplorerSidebarVisible(state, input.workspaceKey) : false, ); - return usesCompactExplorerSidebar(input) ? compactOpen : paneOpen; + return input.isCompact ? compactOpen : paneOpen; } export function isExplorerSidebarOpen(input: ExplorerSidebarQuery): boolean { - if (usesCompactExplorerSidebar(input)) { + if (input.isCompact) { return selectIsCompactFileExplorerOpen(usePanelStore.getState()); } return Boolean( input.workspaceKey && - canUseExplorerSidebar(input) && selectIsExplorerSidebarVisible(useWorkspaceLayoutStore.getState(), input.workspaceKey), ); } diff --git a/packages/app/src/workspace-tabs/launcher/index.tsx b/packages/app/src/workspace-tabs/launcher/index.tsx index afbefcb042..984a756dab 100644 --- a/packages/app/src/workspace-tabs/launcher/index.tsx +++ b/packages/app/src/workspace-tabs/launcher/index.tsx @@ -120,7 +120,6 @@ export function useWorkspaceTabLaunchCatalog(input: { }, [router, serverId]); return useMemo(() => { - const isExplorerMenu = host === "explorer" && surface === "menu"; const changesPresentation = getLaunchPresentation("changes_tree"); const diffPresentation = getLaunchPresentation("working_diff"); const filesPresentation = getLaunchPresentation("files"); @@ -133,7 +132,6 @@ export function useWorkspaceTabLaunchCatalog(input: { shortcutActionId: "workspace-tab-target-agent", disabled: false, panelKind: "draft", - hidden: isExplorerMenu, launch: launchSelection(BUILT_IN_SELECTIONS.agent), }, terminal: { @@ -225,7 +223,7 @@ export function useWorkspaceTabLaunchCatalog(input: { if (pluginItems.length > 0) { groups.push({ id: "plugin-panels", label: null, items: pluginItems }); } - if (!isExplorerMenu && profiles.length > 0) { + if (profiles.length > 0) { groups.push({ id: "terminal-profiles", label: t("workspace.tabs.actions.terminalProfilesMenu"), diff --git a/packages/app/src/workspace-tabs/navigation.test.ts b/packages/app/src/workspace-tabs/navigation.test.ts new file mode 100644 index 0000000000..ab3d1539ab --- /dev/null +++ b/packages/app/src/workspace-tabs/navigation.test.ts @@ -0,0 +1,87 @@ +import { beforeEach, expect, it } from "vitest"; +import { + selectIsExplorerSidebarVisible, + useWorkspaceLayoutStore, +} from "@/stores/workspace-layout-store"; +import { usePanelStore } from "@/stores/panel-store"; +import { revealWorkspaceTab } from "./navigation"; +import { openWorkspaceTargetAtLocation } from "./open-beside"; + +const workspaceKey = "server:workspace"; +beforeEach(() => { + useWorkspaceLayoutStore.setState({ + layoutMode: "split-panes", + layoutByWorkspace: {}, + sheetsByWorkspace: {}, + explorerSidebarPaneIdByWorkspace: {}, + }); + usePanelStore.getState().showMobileFileExplorer(); +}); +it("reveals an existing main file selected from compact Explorer", () => { + const store = useWorkspaceLayoutStore.getState(); + const tabId = store.openTab({ + workspaceKey, + target: { kind: "file", path: "existing.ts" }, + intent: "reveal", + }); + store.setLayoutMode("compact"); + const existing = openWorkspaceTargetAtLocation({ + workspaceKey, + target: { kind: "file", path: "existing.ts" }, + location: "main", + }); + expect(existing).toBe(tabId); + expect(usePanelStore.getState().mobilePanel.target).toBe("agent"); +}); +it("keeps Explorer beneath a new compact file sheet", () => { + const store = useWorkspaceLayoutStore.getState(); + store.setLayoutMode("compact"); + const tabId = openWorkspaceTargetAtLocation({ + workspaceKey, + target: { kind: "file", path: "new.ts" }, + location: "main", + }); + expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); + expect(useWorkspaceLayoutStore.getState().sheetsByWorkspace[workspaceKey]?.[0].tab.tabId).toBe( + tabId, + ); +}); +it("reveals an explicit Explorer target and preserves the surface after a failed open", () => { + const store = useWorkspaceLayoutStore.getState(); + const paneId = store.showExplorerSidebar(workspaceKey)!; + store.setLayoutMode("compact"); + usePanelStore.getState().showMobileAgent(); + const tabId = store.openTab({ + workspaceKey, + target: { kind: "file", path: "draft.ts" }, + intent: "reveal", + placement: { mode: "pane", paneId }, + }); + revealWorkspaceTab(workspaceKey, tabId); + expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); + revealWorkspaceTab(workspaceKey, null); + revealWorkspaceTab(workspaceKey, "missing"); + expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); +}); +it("preserves dock visibility intent while compact targets are opened and revealed", () => { + const store = useWorkspaceLayoutStore.getState(); + const paneId = store.showExplorerSidebar(workspaceKey)!; + store.hideExplorerSidebar(workspaceKey); + store.setLayoutMode("compact"); + store.showExplorerSidebar(workspaceKey); + const tabId = store.openTab({ + workspaceKey, + target: { kind: "file", path: "overlay-only.ts" }, + intent: "reveal", + placement: { mode: "pane", paneId }, + }); + revealWorkspaceTab(workspaceKey, tabId); + store.setLayoutMode("split-panes"); + expect(useWorkspaceLayoutStore.getState().layoutByWorkspace[workspaceKey].root).toBeDefined(); + expect(useWorkspaceLayoutStore.getState().getTabDestination(workspaceKey, tabId!)).toMatchObject({ + host: "explorer", + }); + expect(selectIsExplorerSidebarVisible(useWorkspaceLayoutStore.getState(), workspaceKey)).toBe( + false, + ); +}); diff --git a/packages/app/src/workspace-tabs/navigation.ts b/packages/app/src/workspace-tabs/navigation.ts new file mode 100644 index 0000000000..5e36f65102 --- /dev/null +++ b/packages/app/src/workspace-tabs/navigation.ts @@ -0,0 +1,19 @@ +import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; +import { usePanelStore } from "@/stores/panel-store"; + +/** Reveals the actual destination after placement and deduplication, including existing tabs. */ +export function revealWorkspaceTab(workspaceKey: string, tabId: string | null): string | null { + if (!tabId) return null; + const store = useWorkspaceLayoutStore.getState(); + const destination = store.getTabDestination(workspaceKey, tabId); + // Opening a sheet already reveals it, preserving the surface underneath. + if (!destination) return null; + if (destination.kind === "sheet") return tabId; + store.focusTab(workspaceKey, tabId); + if (store.layoutMode === "compact") { + const panels = usePanelStore.getState(); + if (destination.host === "explorer") panels.showMobileFileExplorer(); + else panels.showMobileAgent(); + } + return tabId; +} diff --git a/packages/app/src/workspace-tabs/open-beside.ts b/packages/app/src/workspace-tabs/open-beside.ts index 0c0c9ebdf5..abf6eba2ec 100644 --- a/packages/app/src/workspace-tabs/open-beside.ts +++ b/packages/app/src/workspace-tabs/open-beside.ts @@ -1,3 +1,4 @@ +import { revealWorkspaceTab } from "./navigation"; import type { OpenInSidePanePreferences } from "@/hooks/use-settings"; import { collectAllTabs, @@ -117,13 +118,16 @@ export function openWorkspaceTargetAtLocation( const parentPane = findPaneContainingTab(layout.root, input.parentTabId); placement = parentPane ? { mode: "prefer", paneId: parentPane.id } : undefined; } - return store.openTab({ - workspaceKey: input.workspaceKey, - target: input.target, - intent: "reveal", - placement, - parentTabId: input.parentTabId ?? undefined, - }); + return revealWorkspaceTab( + input.workspaceKey, + store.openTab({ + workspaceKey: input.workspaceKey, + target: input.target, + intent: "reveal", + placement, + parentTabId: input.parentTabId ?? undefined, + }), + ); } /** Opens a tree selection while reusing an unmodified preview in its destination pane. */ @@ -170,15 +174,21 @@ export function openPreferredWorkspacePreview( nextTarget: input.target, }) ) { - return store.replaceTab(input.workspaceKey, activeTab.tabId, input.target); + return revealWorkspaceTab( + input.workspaceKey, + store.replaceTab(input.workspaceKey, activeTab.tabId, input.target), + ); } - return store.openTab({ - workspaceKey: input.workspaceKey, - target: input.target, - intent: "reveal", - placement: { mode: "pane", paneId: destinationPaneId }, - parentTabId: input.parentTabId ?? activeTab?.tabId ?? undefined, - }); + return revealWorkspaceTab( + input.workspaceKey, + store.openTab({ + workspaceKey: input.workspaceKey, + target: input.target, + intent: "reveal", + placement: { mode: "pane", paneId: destinationPaneId }, + parentTabId: input.parentTabId ?? activeTab?.tabId ?? undefined, + }), + ); } /** @@ -192,11 +202,14 @@ export function openWorkspaceTargetBeside(input: OpenWorkspaceTargetInput): stri } const store = useWorkspaceLayoutStore.getState(); const paneId = store.ensureSidePane(input.workspaceKey); - return store.openTab({ - workspaceKey: input.workspaceKey, - target: input.target, - intent: "reveal", - placement: paneId ? { mode: "pane", paneId } : undefined, - parentTabId: input.parentTabId ?? undefined, - }); + return revealWorkspaceTab( + input.workspaceKey, + store.openTab({ + workspaceKey: input.workspaceKey, + target: input.target, + intent: "reveal", + placement: paneId ? { mode: "pane", paneId } : undefined, + parentTabId: input.parentTabId ?? undefined, + }), + ); } diff --git a/packages/app/src/workspace-tabs/open-supporting-view.test.ts b/packages/app/src/workspace-tabs/open-supporting-view.test.ts index b3e6f4c976..0e423b02c3 100644 --- a/packages/app/src/workspace-tabs/open-supporting-view.test.ts +++ b/packages/app/src/workspace-tabs/open-supporting-view.test.ts @@ -13,6 +13,7 @@ import { usePanelStore } from "@/stores/panel-store"; import { collectAllTabs, findPaneById, + selectExplorerSidebarPaneId, useWorkspaceLayoutStore, } from "@/stores/workspace-layout-store"; import { @@ -23,15 +24,22 @@ import { } from "@/workspace-tabs/open-supporting-view"; const WORKSPACE_KEY = "server-1:workspace-1"; -const CHECKOUT = { serverId: "server-1", cwd: "/tmp/repo", isGit: true }; + +function activeExplorerKind() { + const state = useWorkspaceLayoutStore.getState(); + const layout = state.layoutByWorkspace[WORKSPACE_KEY]; + const paneId = selectExplorerSidebarPaneId(state, WORKSPACE_KEY); + const pane = paneId ? findPaneById(layout.root, paneId) : null; + return collectAllTabs(layout.root).find((tab) => tab.tabId === pane?.focusedTabId)?.target.kind; +} beforeEach(() => { usePanelStore.setState({ mobilePanel: { target: "agent", revision: 0 }, - explorerTab: "files", - explorerTabByCheckout: {}, }); useWorkspaceLayoutStore.setState({ + layoutMode: "split-panes", + sheetsByWorkspace: {}, pullRequestTabAutoOpenedByWorkspace: {}, layoutByWorkspace: {}, explorerSidebarPaneIdByWorkspace: {}, @@ -42,15 +50,15 @@ beforeEach(() => { describe("openWorkspaceChanges", () => { it("opens Changes in the compact Explorer", () => { + useWorkspaceLayoutStore.getState().setLayoutMode("compact"); openWorkspaceChanges({ isCompact: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, preferences: DEFAULT_APP_SETTINGS.openInSidePane, }); expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); - expect(usePanelStore.getState().explorerTab).toBe("changes"); + expect(activeExplorerKind()).toBe("changes_tree"); }); }); @@ -59,7 +67,6 @@ describe("openComposerChanges", () => { isCompact: false, supportsPaneSplits: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, preferences: DEFAULT_APP_SETTINGS.openInSidePane, }; @@ -105,12 +112,12 @@ describe("openComposerChanges", () => { }); it("keeps opening the compact Explorer on Changes", () => { + useWorkspaceLayoutStore.getState().setLayoutMode("compact"); openComposerChanges({ ...input, isCompact: true }); openComposerChanges({ ...input, isCompact: true }); expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); - expect(usePanelStore.getState().explorerTab).toBe("changes"); - expect(useWorkspaceLayoutStore.getState().layoutByWorkspace[WORKSPACE_KEY]).toBeUndefined(); + expect(activeExplorerKind()).toBe("changes_tree"); }); }); @@ -119,17 +126,16 @@ describe("openWorkspacePullRequest", () => { isCompact: false, supportsPaneSplits: true, workspaceKey: WORKSPACE_KEY, - checkout: CHECKOUT, }; it.each(["main", "side", "explorer"] as const)( "opens the compact PR view in Explorer when the desktop preference is %s", (destination) => { + useWorkspaceLayoutStore.getState().setLayoutMode("compact"); openWorkspacePullRequest({ ...input, isCompact: true, destination }); expect(usePanelStore.getState().mobilePanel.target).toBe("file-explorer"); - expect(usePanelStore.getState().explorerTab).toBe("pr"); - expect(useWorkspaceLayoutStore.getState().layoutByWorkspace[WORKSPACE_KEY]).toBeUndefined(); + expect(activeExplorerKind()).toBe("pull_request"); }, ); diff --git a/packages/app/src/workspace-tabs/open-supporting-view.ts b/packages/app/src/workspace-tabs/open-supporting-view.ts index bb567d4bd0..73ae55c31f 100644 --- a/packages/app/src/workspace-tabs/open-supporting-view.ts +++ b/packages/app/src/workspace-tabs/open-supporting-view.ts @@ -1,3 +1,5 @@ +import { supportsDesktopPaneSplits } from "@/constants/layout"; +import { revealWorkspaceTab } from "./navigation"; import { collectAllPanes, collectAllTabs, @@ -8,11 +10,9 @@ import { useWorkspaceLayoutStore, } from "@/stores/workspace-layout-store"; import type { OpenInSidePanePreferences, PullRequestOpenLocation } from "@/hooks/use-settings"; -import type { ExplorerCheckoutContext } from "@/stores/explorer-checkout-context"; import { isExplorerSidebarOpen, openExplorerSidebarView, - usesCompactExplorerSidebar, type ExplorerSidebarView, } from "@/workspace-tabs/explorer-sidebar"; import { @@ -23,7 +23,6 @@ import { interface WorkspaceViewInput { isCompact: boolean; workspaceKey: string | null; - checkout: ExplorerCheckoutContext | null; supportsPaneSplits?: boolean; } @@ -35,13 +34,17 @@ interface OpenWorkspacePullRequestInput extends WorkspaceViewInput { destination: PullRequestOpenLocation; } +function supportingViewsBelongInExplorer(input: WorkspaceViewInput): boolean { + return input.isCompact || !(input.supportsPaneSplits ?? supportsDesktopPaneSplits()); +} + function openExplorerView(input: WorkspaceViewInput, view: ExplorerSidebarView): void { openExplorerSidebarView({ ...input, view }); } /** Opens the workspace Changes view according to the current layout and diff preference. */ export function openWorkspaceChanges(input: OpenWorkspaceChangesInput): string | null { - if (usesCompactExplorerSidebar(input)) { + if (supportingViewsBelongInExplorer(input)) { openExplorerView(input, "changes"); return null; } @@ -55,7 +58,7 @@ export function openWorkspaceChanges(input: OpenWorkspaceChangesInput): string | /** Reveals Changes from the composer, then opens its diff on a subsequent desktop action. */ export function openComposerChanges(input: OpenWorkspaceChangesInput): string | null { - if (usesCompactExplorerSidebar(input) || isExplorerSidebarOpen(input)) { + if (supportingViewsBelongInExplorer(input) || isExplorerSidebarOpen(input)) { return openWorkspaceChanges(input); } openExplorerView(input, "changes"); @@ -64,15 +67,26 @@ export function openComposerChanges(input: OpenWorkspaceChangesInput): string | /** Opens the workspace pull request at its semantic destination. */ export function openWorkspacePullRequest(input: OpenWorkspacePullRequestInput): string | null { - if (usesCompactExplorerSidebar(input) || input.destination === "explorer") { - openExplorerView(input, "pr"); - return null; + if (!input.workspaceKey) return null; + let tabId: string | null; + if (supportingViewsBelongInExplorer(input) || input.destination === "explorer") { + const store = useWorkspaceLayoutStore.getState(); + const paneId = store.ensureExplorerSidebar(input.workspaceKey); + tabId = store.openTab({ + workspaceKey: input.workspaceKey, + target: { kind: "pull_request" }, + intent: "reveal", + placement: paneId ? { mode: "prefer", paneId } : undefined, + }); + } else { + return openWorkspaceTargetAtLocation({ + workspaceKey: input.workspaceKey, + target: { kind: "pull_request" }, + location: input.destination, + }); } - return openWorkspaceTargetAtLocation({ - workspaceKey: input.workspaceKey, - target: { kind: "pull_request" }, - location: input.destination, - }); + revealWorkspaceTab(input.workspaceKey, tabId); + return tabId; } /** Adds a detected desktop PR once without revealing or selecting its destination. */ diff --git a/packages/app/vitest.config.ts b/packages/app/vitest.config.ts index 6274691582..35272f336e 100644 --- a/packages/app/vitest.config.ts +++ b/packages/app/vitest.config.ts @@ -107,6 +107,8 @@ export default defineConfig({ "zustand", "@tanstack/react-query", "react-native-web", + "react-native-reanimated", + "react-native-worklets", "react-native-gesture-handler", "react-native-keyboard-controller", ], diff --git a/packages/desktop/e2e/browser-tabs.e2e.mjs b/packages/desktop/e2e/browser-tabs.e2e.mjs index fb0958aad1..af142e6385 100644 --- a/packages/desktop/e2e/browser-tabs.e2e.mjs +++ b/packages/desktop/e2e/browser-tabs.e2e.mjs @@ -12,6 +12,7 @@ import { fileURLToPath } from "node:url"; import { experimental_createMCPClient } from "ai"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { chromium } from "playwright"; +import { installDeveloperToastDismissal } from "../../app/e2e/support/developer-ui.mjs"; import { runAppearanceFontSizeRegression } from "./appearance-font-size.electron.mjs"; import { runSettingsMemoryRegression } from "./settings-memory.electron.mjs"; @@ -1173,6 +1174,7 @@ async function main() { cwd: rootDir, env: { ...commonEnv, + EXPO_UNSTABLE_HEADLESS: "1", EXPO_PORT: String(expoPort), EXPO_DEV_URL: `http://localhost:${expoPort}`, PASEO_ELECTRON_REMOTE_DEBUGGING_PORT: String(cdpPort), @@ -1187,6 +1189,7 @@ async function main() { browser = await chromium.connectOverCDP(`http://127.0.0.1:${cdpPort}`); const page = await waitForAppPage(browser, expoPort); + await installDeveloperToastDismissal(page); const status = await waitForDesktopStatus(page); const checkPluginLinks = () => diff --git a/packages/desktop/e2e/daemon-lifecycle-renderer.electron.mjs b/packages/desktop/e2e/daemon-lifecycle-renderer.electron.mjs index d32b7d65b8..a98a158511 100644 --- a/packages/desktop/e2e/daemon-lifecycle-renderer.electron.mjs +++ b/packages/desktop/e2e/daemon-lifecycle-renderer.electron.mjs @@ -35,6 +35,7 @@ export async function verifyAttachedDaemonControls({ repo, root, env, home, port env: { ...env, EXPO_NO_DOTENV: "1", + EXPO_UNSTABLE_HEADLESS: "1", CI: "1", PASEO_WEB_PLATFORM: "electron", EXPO_PUBLIC_LOCAL_DAEMON: `127.0.0.1:${port}`, diff --git a/packages/expo-two-way-audio/ios/ExpoTwoWayAudioModule.swift b/packages/expo-two-way-audio/ios/ExpoTwoWayAudioModule.swift index 046f856747..b18afd7deb 100644 --- a/packages/expo-two-way-audio/ios/ExpoTwoWayAudioModule.swift +++ b/packages/expo-two-way-audio/ios/ExpoTwoWayAudioModule.swift @@ -152,7 +152,7 @@ public class ExpoTwoWayAudioModule: Module { EXPermissionsMethodsDelegate.getPermissionWithPermissionsManager( self.appContext?.permissions, withRequester: MicrophonePermissionRequester.self, - resolve: promise.resolver, + resolve: promise.legacyResolver, reject: promise.legacyRejecter ) } @@ -161,7 +161,7 @@ public class ExpoTwoWayAudioModule: Module { EXPermissionsMethodsDelegate.askForPermission( withPermissionsManager: self.appContext?.permissions, withRequester: MicrophonePermissionRequester.self, - resolve: promise.resolver, + resolve: promise.legacyResolver, reject: promise.legacyRejecter ) } diff --git a/packages/expo-two-way-audio/ios/MicrophonePermissionRequester.swift b/packages/expo-two-way-audio/ios/MicrophonePermissionRequester.swift index fb81f461c1..14dc7a2ee5 100644 --- a/packages/expo-two-way-audio/ios/MicrophonePermissionRequester.swift +++ b/packages/expo-two-way-audio/ios/MicrophonePermissionRequester.swift @@ -15,11 +15,11 @@ class MicrophonePermissionRequester: NSObject, EXPermissionsRequester { var status: EXPermissionStatus guard (Bundle.main.infoDictionary?["NSMicrophoneUsageDescription"]) != nil else { - EXFatal(EXErrorWithMessage(""" + log.error(""" This app is missing NSMicrophoneUsageDescription, so audio services will fail. Add one of these keys to your bundle's Info.plist. - """)) - return ["status": EXPermissionStatusDenied] + """) + return ["status": EXPermissionStatusDenied.rawValue] } switch systemStatus { diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 0162b085f3..624e4e42d5 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -74,8 +74,8 @@ "@getpaseo/protocol": "0.12.0", "@types/node": "^20.9.0", "@types/react": "~19.2.0", - "react": "19.1.0", - "react-native": "0.81.5", + "react": "19.2.3", + "react-native": "0.86.3", "typescript": "^5.9.3", "vitest": "^4.1.6", "zod": "^4.4.3" @@ -83,7 +83,7 @@ "peerDependencies": { "@getpaseo/client": "0.12.0", "@getpaseo/protocol": "0.12.0", - "react": "~19.1.0", + "react": ">=19.1.0 <20", "react-native": ">=0.81.5", "zod": "^4.4.3" }, diff --git a/packages/server/src/server/workspace-create-worktree-source.e2e.test.ts b/packages/server/src/server/workspace-create-worktree-source.e2e.test.ts index 6e757c3770..80208fe63d 100644 --- a/packages/server/src/server/workspace-create-worktree-source.e2e.test.ts +++ b/packages/server/src/server/workspace-create-worktree-source.e2e.test.ts @@ -625,8 +625,9 @@ test("setup details follow one workspace/source and restore after reconnect with path.join(repoDir, "setup.cjs"), ` const fs = require('node:fs'); +// Exercise a real child start beyond Vitest's default one-second polling window. +setTimeout(() => { console.log('setup started'); -fs.writeFileSync('started.txt', 'ready'); let wave = 0; const timer = setInterval(() => { if (fs.existsSync('wave-' + wave)) { @@ -636,6 +637,7 @@ const timer = setInterval(() => { } if (fs.existsSync('finish.txt')) { clearInterval(timer); process.exit(1); } }, 20); +}, 1500); `, ); writeFileSync(path.join(repoDir, ".gitignore"), "*.txt\nwave-*\nemitted-*\n"); @@ -672,15 +674,25 @@ const timer = setInterval(() => { const directory = quiet.observeWorkspaces(); observations.push(directory); await directory.ready; + const waitForSetupStarted = async (workspaceId: string) => { + // Process startup is asynchronous, especially under Windows PowerShell. The daemon's + // output snapshot is the readiness barrier; a marker file can precede PTY delivery. + await expect + .poll(async () => (await viewer.fetchWorkspaceSetupStatus(workspaceId)).snapshot, { + timeout: 30000, + }) + .toMatchObject({ + status: "running", + detail: { log: expect.stringContaining("setup started") }, + }); + }; for (const worktreeSlug of ["noisy-a", "noisy-b", "noisy-c"]) { const result = await creator.createWorkspace({ source: { kind: "worktree", cwd: repoDir, worktreeSlug }, }); if (!result.workspace || result.error) throw new Error(result.error ?? "No workspace"); workspaces.push(result.workspace); - await expect - .poll(() => existsSync(path.join(result.workspace!.workspaceDirectory!, "started.txt"))) - .toBe(true); + await waitForSetupStarted(result.workspace.id); } const external = await mcp.callTool({ name: "create_workspace", @@ -693,17 +705,8 @@ const timer = setInterval(() => { ); if (!externalWorkspace) throw new Error("Missing MCP directory entry"); workspaces.unshift(externalWorkspace); - await expect - .poll(() => existsSync(path.join(externalWorkspace.workspaceDirectory!, "started.txt"))) - .toBe(true); + await waitForSetupStarted(externalWorkspace.id); const workspace = workspaces[0]!; - // The child writes its marker before the terminal's output is delivered. - // Wait for the daemon snapshot, rather than treating the file as an output barrier. - await expect - .poll(async () => (await viewer.fetchWorkspaceSetupStatus(workspace.id)).snapshot, { - timeout: 30000, - }) - .toMatchObject({ detail: { log: expect.stringContaining("setup started") } }); const details = viewer.observeWorkspaceSetup(workspace.id); observations.push(details); const initial = await details.ready; diff --git a/patches/react-native-gesture-handler+2.28.0.patch b/patches/react-native-gesture-handler+2.32.0.patch similarity index 79% rename from patches/react-native-gesture-handler+2.28.0.patch rename to patches/react-native-gesture-handler+2.32.0.patch index ada7b3a511..af0941ac46 100644 --- a/patches/react-native-gesture-handler+2.28.0.patch +++ b/patches/react-native-gesture-handler+2.32.0.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt -index a532cf6..7b66222 100644 +index 8d78aea..02e3ea6 100644 --- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt +++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/core/GestureHandlerOrchestrator.kt @@ -2,6 +2,7 @@ package com.swmansion.gesturehandler.core @@ -10,7 +10,7 @@ index a532cf6..7b66222 100644 import android.view.MotionEvent import android.view.View import android.view.ViewGroup -@@ -24,6 +25,10 @@ class GestureHandlerOrchestrator( +@@ -28,6 +29,10 @@ class GestureHandlerOrchestrator( private val awaitingHandlers = arrayListOf() private val preparedHandlers = arrayListOf() @@ -21,7 +21,7 @@ index a532cf6..7b66222 100644 // In `onHandlerStateChange` method we iterate through `awaitingHandlers`, but calling `tryActivate` may modify this list. // To avoid `ConcurrentModificationException` we iterate through copy. There is one more problem though - if handler was // removed from `awaitingHandlers`, it was still present in copy of original list. This hashset helps us identify which handlers -@@ -42,6 +47,7 @@ class GestureHandlerOrchestrator( +@@ -46,6 +51,7 @@ class GestureHandlerOrchestrator( fun onTouchEvent(event: MotionEvent): Boolean { isHandlingTouch = true val action = event.actionMasked @@ -29,9 +29,9 @@ index a532cf6..7b66222 100644 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN || action == MotionEvent.ACTION_HOVER_MOVE -@@ -562,6 +568,107 @@ class GestureHandlerOrchestrator( - extractGestureHandlers(wrapperView, tempCoords, pointerId, event) - } +@@ -579,6 +585,107 @@ class GestureHandlerOrchestrator( + private fun shouldIgnoreSubtreeIfGestureHandlerRootView(view: View) = + view is RNGestureHandlerRootView && view != wrapperView && view.isRootViewEnabled() + private fun trackPointerDownPoints(event: MotionEvent) { + val index = event.actionIndex @@ -138,7 +138,7 @@ index a532cf6..7b66222 100644 viewGroup: ViewGroup, coords: FloatArray, diff --git a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt -index d8f8fd6..ed101b9 100644 +index 629c155..e1909ff 100644 --- a/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt +++ b/node_modules/react-native-gesture-handler/android/src/main/java/com/swmansion/gesturehandler/react/RNGestureHandlerRootHelper.kt @@ -19,6 +19,7 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView: @@ -149,9 +149,9 @@ index d8f8fd6..ed101b9 100644 private var passingTouch = false init { -@@ -117,6 +118,14 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView: +@@ -118,6 +119,14 @@ class RNGestureHandlerRootHelper(private val context: ReactContext, wrappedView: passingTouch = true - orchestrator!!.onTouchEvent(ev) + orchestrator!!.onTouchEvent(event) passingTouch = false + + // On the transition into interception, cancel the native views the pointers landed on - the @@ -164,6 +164,21 @@ index d8f8fd6..ed101b9 100644 return shouldIntercept } +diff --git a/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js b/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js +index 96c5227..cbf1a88 100644 +--- a/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js ++++ b/node_modules/react-native-gesture-handler/lib/commonjs/web/handlers/GestureHandler.js +@@ -58,7 +58,9 @@ class GestureHandler { + manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this)); + manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this)); + manager.setOnWheel(this.onWheel.bind(this)); +- manager.registerListeners(); ++ if (this.enabled) { ++ manager.registerListeners(); ++ } + } + + // diff --git a/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js b/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js index 76eb808..7c40526 100644 --- a/node_modules/react-native-gesture-handler/lib/commonjs/web/tools/PointerEventManager.js @@ -184,6 +199,21 @@ index 76eb808..7c40526 100644 } this.markAsOutOfBounds(adaptedEvent.pointerId); this.trackedPointers.delete(adaptedEvent.pointerId); +diff --git a/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js b/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js +index 0791c66..2f41c77 100644 +--- a/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js ++++ b/node_modules/react-native-gesture-handler/lib/module/web/handlers/GestureHandler.js +@@ -52,7 +52,9 @@ export default class GestureHandler { + manager.setOnPointerMoveOver(this.onPointerMoveOver.bind(this)); + manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this)); + manager.setOnWheel(this.onWheel.bind(this)); +- manager.registerListeners(); ++ if (this.enabled) { ++ manager.registerListeners(); ++ } + } + + // diff --git a/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js b/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js index 6ce3b8f..8fe28bc 100644 --- a/node_modules/react-native-gesture-handler/lib/module/web/tools/PointerEventManager.js @@ -204,6 +234,21 @@ index 6ce3b8f..8fe28bc 100644 } this.markAsOutOfBounds(adaptedEvent.pointerId); this.trackedPointers.delete(adaptedEvent.pointerId); +diff --git a/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts b/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts +index ddb79a3..4e1274c 100644 +--- a/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts ++++ b/node_modules/react-native-gesture-handler/src/web/handlers/GestureHandler.ts +@@ -79,7 +79,9 @@ export default abstract class GestureHandler implements IGestureHandler { + manager.setOnPointerMoveOut(this.onPointerMoveOut.bind(this)); + manager.setOnWheel(this.onWheel.bind(this)); + +- manager.registerListeners(); ++ if (this.enabled) { ++ manager.registerListeners(); ++ } + } + + // diff --git a/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts b/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts index 18d3627..769b0fe 100644 --- a/node_modules/react-native-gesture-handler/src/web/tools/PointerEventManager.ts diff --git a/patches/react-native-svg+15.15.3.patch b/patches/react-native-svg+15.15.4.patch similarity index 100% rename from patches/react-native-svg+15.15.3.patch rename to patches/react-native-svg+15.15.4.patch diff --git a/scripts/postinstall-patches.mjs b/scripts/postinstall-patches.mjs index 5a2e62c5c6..638c62de55 100644 --- a/scripts/postinstall-patches.mjs +++ b/scripts/postinstall-patches.mjs @@ -36,8 +36,9 @@ const patchedPackages = [ patchPrefix: "@gorhom+bottom-sheet+", }, { - nodeModulesPath: "node_modules/react-native-svg", + nodeModulesPath: "packages/app/node_modules/react-native-svg", patchPrefix: "react-native-svg+", + cwd: "packages/app", }, { nodeModulesPath: "node_modules/@mattermost/react-native-paste-input",