From 5cc99e1c23980d7995a13c47f969b47cb68ed1be Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 1 Oct 2026 02:10:50 -0700 Subject: [PATCH 01/32] fix(desktop): agent clicks in the browser no longer pop Save dialogs (#14573) Co-authored-by: Claude Opus 5.5 (1M context) --- apps/desktop/src/preview/Manager.test.ts | 120 ++++++++++++++++++++++- apps/desktop/src/preview/Manager.ts | 40 +++++++- 2 files changed, 157 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/preview/Manager.test.ts b/apps/desktop/src/preview/Manager.test.ts index 304efeafefe9..d3f6971b820b 100644 --- a/apps/desktop/src/preview/Manager.test.ts +++ b/apps/desktop/src/preview/Manager.test.ts @@ -186,6 +186,7 @@ const { fromId, getFocusedWebContents, mkdir, + previewSession, showItemInFolder, webviewSend, writeFile, @@ -200,6 +201,7 @@ const { fromId: vi.fn<(_id?: number) => Electron.WebContents | null>((_id?: number) => null), getFocusedWebContents: vi.fn(() => null), mkdir: vi.fn((_path: string) => undefined), + previewSession: { on: vi.fn() }, showItemInFolder: vi.fn(), webviewSend: vi.fn(), writeFile: vi.fn((_path: string, _data: Uint8Array) => undefined), @@ -236,7 +238,7 @@ const browserSessionLayer = Layer.succeed( BrowserSession.BrowserSession.of({ getPartition: () => Effect.succeed("persist:t3code-preview-test"), isPartition: (partition) => partition.startsWith("persist:t3code-preview-"), - getSession: () => Effect.die("unexpected getSession"), + getSession: () => Effect.succeed(previewSession as unknown as Electron.Session), clearCookies: () => Effect.void, clearCache: () => Effect.void, }), @@ -547,6 +549,7 @@ describe("PreviewManager", () => { getFocusedWebContents.mockReset(); getFocusedWebContents.mockReturnValue(null); mkdir.mockClear(); + previewSession.on.mockClear(); writeFile.mockClear(); showItemInFolder.mockClear(); clipboardItemConstructor.mockClear(); @@ -4536,6 +4539,121 @@ describe("PreviewManager", () => { }), ), ); + effectIt.effect("saves downloads from agent-driven pages without a Save dialog", () => + withManager((manager) => + Effect.gen(function* () { + let humanInput: ((event: unknown, signal?: unknown) => void) | undefined; + const wc = makeTestPreviewWebContents(vi.fn()); + Object.assign(wc, { + isDevToolsOpened: () => false, + loadURL: vi.fn(async () => undefined), + reload: vi.fn(), + }); + Object.assign(wc.ipc, { + on: vi.fn((channel: string, listener: typeof humanInput) => { + if (channel === "preview:human-input") humanInput = listener; + }), + }); + let holdEvaluate = false; + let releaseEvaluate: (() => void) | undefined; + Object.assign(wc.debugger, { + sendCommand: vi.fn(async (method: string, params?: { expression?: string }) => { + if (method !== "Runtime.evaluate") return undefined; + if (params?.expression?.includes("matched")) + return { result: { value: { matched: true } } }; + if (holdEvaluate) { + holdEvaluate = false; + await new Promise((resolve) => { + releaseEvaluate = resolve; + }); + } + return { result: { value: 42 } }; + }), + }); + fromId.mockReturnValue(wc); + const takeovers = [yield* Deferred.make(), yield* Deferred.make()]; + let takeoverCount = 0; + let controller = "none"; + yield* manager.subscribeStateChanges((_tabId, state) => { + const takeover = + controller !== "human" && state.controller === "human" + ? takeovers[takeoverCount++] + : undefined; + controller = state.controller; + return takeover ? Deferred.succeed(takeover, undefined).pipe(Effect.asVoid) : Effect.void; + }); + yield* manager.getBrowserSession(); + yield* manager.getBrowserSession(); + const installs = previewSession.on.mock.calls.filter( + ([event]) => event === "will-download", + ); + expect(installs).toHaveLength(1); + const willDownload = installs[0]![1] as ( + event: unknown, + item: { + getFilename: () => string; + getStartTime: () => number; + setSavePath: (path: string) => void; + }, + source: Electron.WebContents, + ) => void; + const download = () => { + const setSavePath = vi.fn(); + willDownload( + {}, + { getFilename: () => "chart.png", getStartTime: () => 1_790_844_530.5, setSavePath }, + wc, + ); + return setSavePath; + }; + yield* manager.createTab("tab_1"); + yield* manager.registerWebview("tab_1", 42); + + expect(download()).not.toHaveBeenCalled(); + + yield* manager.automationEvaluate("tab_1", { expression: "42" }); + const startedAt = (1_790_844_530_500).toString(36); + expect(download()).toHaveBeenCalledWith( + `/tmp/t3/dev/browser-artifacts/browser-download-${startedAt}-0-chart.png`, + ); + // Same name, same millisecond: still a separate file. + expect(download()).toHaveBeenCalledWith( + `/tmp/t3/dev/browser-artifacts/browser-download-${startedAt}-1-chart.png`, + ); + + humanInput?.({}, { kind: "pointer", x: 10, y: 10, button: 0 }); + yield* Deferred.await(takeovers[0]!); + expect(download()).not.toHaveBeenCalled(); + + // An action still waiting for the page when the human takes over must + // not mark it as agent-driven again. + holdEvaluate = true; + const running = yield* manager + .automationEvaluate("tab_1", { expression: "42" }) + .pipe(Effect.forkChild({ startImmediately: true })); + yield* settle(() => releaseEvaluate !== undefined); + const queued = yield* manager + .automationEvaluate("tab_1", { expression: "42" }) + .pipe(Effect.forkChild({ startImmediately: true })); + humanInput?.({}, { kind: "pointer", x: 20, y: 20, button: 0 }); + yield* Deferred.await(takeovers[1]!); + releaseEvaluate?.(); + yield* Fiber.await(running); + expect(Exit.isFailure(yield* Fiber.await(queued))).toBe(true); + expect(download()).not.toHaveBeenCalled(); + + // URL-bar navigation hands the page back to the human. + yield* manager.automationEvaluate("tab_1", { expression: "42" }); + expect(download()).toHaveBeenCalled(); + yield* manager.navigate("tab_1", "https://example.com/report.csv"); + expect(download()).not.toHaveBeenCalled(); + + // Reading the page does not make it agent-driven. + yield* manager.automationWaitFor("tab_1", { text: "Example" }); + expect(download()).not.toHaveBeenCalled(); + }), + ), + ); }); describe("PreviewOperationError", () => { diff --git a/apps/desktop/src/preview/Manager.ts b/apps/desktop/src/preview/Manager.ts index b97af6f05204..cc1a8f524dc8 100644 --- a/apps/desktop/src/preview/Manager.ts +++ b/apps/desktop/src/preview/Manager.ts @@ -520,6 +520,9 @@ interface ExpectedAgentInput { */ const POPUP_PROTOCOLS = new Set(["http:", "https:"]); +/** Control actions that only read the page, so they do not make it agent-driven. */ +const READ_ONLY_CONTROL_ACTIONS = new Set(["snapshot", "waitFor"]); + const isPopupUrl = (rawUrl: string): boolean => { try { return POPUP_PROTOCOLS.has(new URL(rawUrl).protocol); @@ -685,6 +688,10 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function // (electron#44618) and now always rejects with NotAllowedError. let pendingRecording: PendingRecording | null = null; const displayMediaHandlerSessions = new WeakSet(); + const downloadHandlerSessions = new WeakSet(); + let downloadCount = 0; + // Preview pages whose latest input came from an agent action, not the human. + const agentDrivenWebContents = new WeakSet(); let frameCaptureWindowOpen = true; let currentMainWindow: BrowserWindow | undefined; let mainWindowCleanupFiber: Fiber.Fiber | undefined; @@ -1487,7 +1494,6 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function const epoch = (yield* Ref.get(controlEpochRef)).get(tabId) ?? 0; const control = yield* ensureControlSession(wc); const execute = Effect.fn("PreviewManager.executeControlAction")(function* () { - yield* update(tabId, { controller: "agent" }); const checkControl = Effect.gen(function* () { const currentEpoch = (yield* Ref.get(controlEpochRef)).get(tabId) ?? 0; if (currentEpoch !== epoch) { @@ -1498,6 +1504,11 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function }); } }); + // A human who took over while this action waited for the permit owns + // the page; marking it agent-driven would hide their Save dialog. + yield* checkControl; + if (!READ_ONLY_CONTROL_ACTIONS.has(action)) agentDrivenWebContents.add(wc); + yield* update(tabId, { controller: "agent" }); const send: SendCommand = Effect.fn("PreviewManager.sendCommand")( function* (method, commandParams, sessionId) { yield* checkControl; @@ -1922,6 +1933,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function if (isPreviewInputSignal(rawSignal) && (yield* consumeExpectedAgentInput(tabId, rawSignal))) { return; } + agentDrivenWebContents.delete(wc); yield* Ref.update(controlEpochRef, (epochs) => replaceMap(epochs, (copy) => { copy.set(tabId, (epochs.get(tabId) ?? 0) + 1); @@ -2476,6 +2488,9 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function ); return; } + // URL-bar navigation hands the page back to the human. The agent's own + // navigation shares this path; its next action marks the page again. + agentDrivenWebContents.delete(wc); if (wc.getURL() === url) { yield* attempt({ operation: "navigate.reload", tabId, webContentsId: wc.id }, () => wc.reload(), @@ -3500,6 +3515,24 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function }); }; + // Installed once per session. Electron opens a native Save dialog for a + // download with no save path, so every export an agent clicked while testing + // a page put a modal over the whole app. Downloads from a page the agent drove + // last go to the artifact directory instead. Downloads the human starts keep + // the Save dialog. + const installDownloadHandler = (session: Session) => { + if (downloadHandlerSessions.has(session)) return; + downloadHandlerSessions.add(session); + session.on("will-download", (_event, item, source) => { + if (!agentDrivenWebContents.has(source)) return; + // The start time keeps names unique across restarts; the count keeps two + // same-name downloads in one millisecond from overwriting each other. + const id = `${Math.round(item.getStartTime() * 1000).toString(36)}-${(downloadCount++).toString(36)}`; + const fileName = `browser-download-${id}-${path.basename(item.getFilename())}`; + item.setSavePath(path.join(resolvedArtifactDirectory, fileName)); + }); + }; + const startRecording = Effect.fn("PreviewManager.startRecording")(function* ( tabId: string, options: RecordingInputOptions = DEFAULT_RECORDING_INPUT_OPTIONS, @@ -4624,6 +4657,7 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function goBack, goForward, hardReload, + installDownloadHandler, navigate, openPictureInPicture, openDevTools, @@ -5075,13 +5109,15 @@ export const make = Effect.gen(function* PreviewManagerMake() { setMainWindow: operations.setMainWindow, getBrowserSession: Effect.fn("PreviewManager.getBrowserSession")( function* (scope, persistent, namespace) { - return yield* browserSession + const session = yield* browserSession .getSession(scope, persistent, namespace) .pipe( Effect.mapError( (cause) => new PreviewOperationError({ operation: "getBrowserSession", cause }), ), ); + operations.installDownloadHandler(session); + return session; }, ), isBrowserPartition: browserSession.isPartition, From 8dc07f199c2e3a4d8ec1a3997a2b9c2edf12457e Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:22 -0700 Subject: [PATCH 02/32] chore(mobile): upgrade to Expo SDK 58 and React Native 0.88 RC (#12045) Co-authored-by: Claude Fable 5 --- apps/mobile/app.config.ts | 4 +- .../t3-markdown-text/ios/T3MarkdownText.mm | 2 +- .../ios/T3MarkdownTextManager.mm | 1 - .../t3-markdown-text/ios/T3MarkdownTextRun.mm | 2 +- .../src/MarkdownTextPrimitive.tsx | 13 +- .../src/NativeMarkdownSelectableText.tsx | 30 +- .../src/T3MarkdownTextNativeComponent.ts | 24 +- .../src/T3MarkdownTextRunNativeComponent.ts | 40 +- .../t3-markdown-text/src/markdownFileIcons.ts | 11 +- apps/mobile/package.json | 95 +- apps/mobile/plugins/withIosSceneLifecycle.cjs | 123 - .../plugins/withIosSceneLifecycle.test.mjs | 58 - apps/mobile/src/App.tsx | 5 +- apps/mobile/src/Stack.tsx | 12 +- .../src/components/AndroidAnchoredMenu.tsx | 6 +- apps/mobile/src/components/AppText.tsx | 3 +- .../components/ComposerAttachmentStrip.tsx | 2 +- apps/mobile/src/components/GlassSurface.tsx | 11 +- apps/mobile/src/components/LoadingScreen.tsx | 2 +- .../src/components/MaterialSearchField.tsx | 4 +- .../src/components/ScreenHeader.android.tsx | 11 +- .../src/connection/background-activity.ts | 6 +- .../foregroundNotificationBehavior.test.ts | 61 + .../foregroundNotificationBehavior.ts | 35 + .../agent-awareness/notificationNavigation.ts | 19 +- .../agent-awareness/notificationPayload.ts | 13 + .../archive/ArchivedThreadsScreen.tsx | 10 +- .../connection/CloudEnvironmentRows.tsx | 10 +- .../features/devices/DeviceStreamWebView.tsx | 4 +- .../features/files/MaterialFilesHeader.tsx | 4 +- apps/mobile/src/features/home/HomeScreen.tsx | 8 +- .../home/MaterialThreadListToolbar.tsx | 10 +- .../features/home/thread-swipe-actions.tsx | 8 +- .../src/features/keyboard/CommandPalette.tsx | 3 +- .../sharing/incoming-share-storage.ts | 2 +- .../terminal/NativeTerminalSurface.tsx | 3 +- .../threads/CustomSnoozeSheet.ios.tsx | 6 +- .../features/threads/ThreadDetailScreen.tsx | 3 +- .../threads/ThreadNavigationSidebar.tsx | 8 +- .../features/threads/thread-list-v2-items.tsx | 6 +- apps/mobile/src/lib/atomic-file.ts | 2 +- apps/mobile/src/lib/attachmentUpload.ts | 2 +- apps/mobile/src/lib/composerImages.ts | 4 +- .../src/native/T3ComposerEditor.ios.tsx | 11 +- .../src/native/T3ComposerEditor.native.tsx | 9 +- apps/mobile/src/native/T3ComposerEditor.tsx | 4 +- .../src/native/T3KeyboardCommands.android.tsx | 2 +- .../src/native/T3KeyboardCommands.ios.tsx | 2 +- apps/mobile/src/widgets/SubscriptionUsage.tsx | 2 +- apps/mobile/tsconfig.json | 2 +- apps/web/package.json | 2 +- patches/@clerk__expo@4.6.8.patch | 17 + ...patch => @expo__metro-config@58.0.6.patch} | 32 +- patches/@react-native-menu__menu@2.0.0.patch | 8 + ...o@57.0.4.patch => expo-audio@58.0.3.patch} | 5 +- patches/expo-blur@58.0.2.patch | 57 + patches/expo-glass-effect@58.0.3.patch | 72 + ....0.17.patch => expo-sharing@58.0.12.patch} | 12 +- ...7.0.15.patch => expo-widgets@58.0.9.patch} | 48 +- .../react-native-gesture-handler@2.32.0.patch | 237 -- .../react-native-gesture-handler@3.2.1.patch | 151 + ...t-native-keyboard-controller@1.22.4.patch} | 162 +- .../react-native-nitro-modules@0.35.9.patch | 16 + patches/react-native-reanimated@4.5.5.patch | 69 - ...atch => react-native-screens@4.28.0.patch} | 278 +- pnpm-lock.yaml | 3581 ++++++----------- pnpm-workspace.yaml | 107 +- third-party-licenses.config.json | 81 + 68 files changed, 2423 insertions(+), 3230 deletions(-) delete mode 100644 apps/mobile/plugins/withIosSceneLifecycle.cjs delete mode 100644 apps/mobile/plugins/withIosSceneLifecycle.test.mjs create mode 100644 apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.test.ts create mode 100644 apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.ts rename patches/{@expo__metro-config@57.0.12.patch => @expo__metro-config@58.0.6.patch} (73%) rename patches/{expo-audio@57.0.4.patch => expo-audio@58.0.3.patch} (80%) create mode 100644 patches/expo-blur@58.0.2.patch create mode 100644 patches/expo-glass-effect@58.0.3.patch rename patches/{expo-sharing@57.0.17.patch => expo-sharing@58.0.12.patch} (91%) rename patches/{expo-widgets@57.0.15.patch => expo-widgets@58.0.9.patch} (80%) delete mode 100644 patches/react-native-gesture-handler@2.32.0.patch create mode 100644 patches/react-native-gesture-handler@3.2.1.patch rename patches/{react-native-keyboard-controller@1.21.13.patch => react-native-keyboard-controller@1.22.4.patch} (89%) delete mode 100644 patches/react-native-reanimated@4.5.5.patch rename patches/{react-native-screens@4.26.2.patch => react-native-screens@4.28.0.patch} (94%) diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index 52eae6db9777..6a992e6c5264 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -401,6 +401,9 @@ const config: ExpoConfig = { android: { // Keep the supported floor explicit and covered by native notification tests. minSdkVersion: 24, + // kotlinx-io uses Kotlin 2.3's return-value checker annotation, while + // SDK 58 builds with Kotlin 2.2. It has no runtime behavior. + extraProguardRules: "-dontwarn kotlin.MustUseReturnValues", }, ios: { deploymentTarget: "18.0", @@ -419,7 +422,6 @@ const config: ExpoConfig = { // would delete the asset catalog) and its xcodeproj mod creates the widget // target (which must exist before the compile phase can be attached). ...(!isIosPersonalTeamBuild ? ["./plugins/withWidgetLogoAsset.cjs", widgetsPlugin] : []), - "./plugins/withIosSceneLifecycle.cjs", "./plugins/withAndroidCleartextTraffic.cjs", "./plugins/withAndroidGradleHeap.cjs", "./plugins/withAndroidInputBackground.cjs", diff --git a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownText.mm b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownText.mm index 533c13108865..8fa5abfe2a8e 100644 --- a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownText.mm +++ b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownText.mm @@ -10,7 +10,7 @@ #import #import #import -#import "RCTFabricComponentsPlugins.h" +#import using namespace facebook::react; diff --git a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextManager.mm b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextManager.mm index 3ca2b1eee5b9..93f1b2e4ba2a 100644 --- a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextManager.mm +++ b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextManager.mm @@ -1,6 +1,5 @@ #import #import -#import "RCTBridge.h" #import "Utils.h" @interface T3MarkdownTextManager : RCTViewManager diff --git a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextRun.mm b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextRun.mm index d2de6884396f..2cd9444f6d22 100644 --- a/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextRun.mm +++ b/apps/mobile/modules/t3-markdown-text/ios/T3MarkdownTextRun.mm @@ -4,7 +4,7 @@ #import #import #import -#import "RCTFabricComponentsPlugins.h" +#import #import "Utils.h" using namespace facebook::react; diff --git a/apps/mobile/modules/t3-markdown-text/src/MarkdownTextPrimitive.tsx b/apps/mobile/modules/t3-markdown-text/src/MarkdownTextPrimitive.tsx index 1e9394bd6eca..2e8026f32828 100644 --- a/apps/mobile/modules/t3-markdown-text/src/MarkdownTextPrimitive.tsx +++ b/apps/mobile/modules/t3-markdown-text/src/MarkdownTextPrimitive.tsx @@ -6,6 +6,7 @@ import { StyleSheet, Text as RNText, type ColorValue, + type TextInstance, type TextProps, type ViewStyle, } from "react-native"; @@ -43,7 +44,7 @@ export type ContextMenuActionEvent = { * while the React Native Text fallback reports measured `TextLayoutLine`s. */ export type MarkdownTextPrimitiveProps = Omit & { - nativeTextRef?: Ref; + nativeTextRef?: Ref; selectionHandleColor?: ColorValue; uiTextView?: boolean; contextMenuConfig?: string; @@ -134,13 +135,17 @@ function AndroidMarkdownText({ contextClipboardConfig: _contextClipboardConfig, ...props }: MarkdownTextPrimitiveProps) { - const textRef = React.useRef(null); - React.useImperativeHandle(nativeTextRef, () => textRef.current, []); + const textRef = React.useRef(null); + React.useImperativeHandle( + nativeTextRef, + () => textRef.current, + [], + ); const color = processColor(selectionHandleColor); const applyHandleColor = React.useCallback(() => { if (!textRef.current || typeof color !== "number") return; const reactTag = findNodeHandle(textRef.current); - if (reactTag !== null) setMarkdownSelectionHandleColor(reactTag, color); + if (reactTag != null) setMarkdownSelectionHandleColor(reactTag, color); }, [color]); // RN's selectionColor only sets the highlight. Retint mounted handles when diff --git a/apps/mobile/modules/t3-markdown-text/src/NativeMarkdownSelectableText.tsx b/apps/mobile/modules/t3-markdown-text/src/NativeMarkdownSelectableText.tsx index 1d9c2b93ede8..5a01dd436bbc 100644 --- a/apps/mobile/modules/t3-markdown-text/src/NativeMarkdownSelectableText.tsx +++ b/apps/mobile/modules/t3-markdown-text/src/NativeMarkdownSelectableText.tsx @@ -6,14 +6,14 @@ import { Linking, Platform, StyleSheet, - Text as RNText, + type TextInstance, type TextStyle, useColorScheme, View, } from "react-native"; import { MarkdownTextPrimitive } from "./MarkdownTextPrimitive"; -import { markdownFileIconSource } from "./markdownFileIcons"; +import { markdownFileIconSource, markdownIconAssetUri } from "./markdownFileIcons"; import { markdownLinkIconSource } from "./markdownLinkIcons"; import { resolveMarkdownFileIcon, resolveMarkdownLinkIcon } from "./markdownLinks"; import type { NativeMarkdownTextRun } from "./nativeMarkdownText"; @@ -236,11 +236,11 @@ export function NativeMarkdownSelectableText(props: { interactive: Boolean(run.href), iconUri: !contextReference && run.fileIcon - ? Image.resolveAssetSource(markdownFileIconSource(run.fileIcon)).uri + ? markdownIconAssetUri(markdownFileIconSource(run.fileIcon)) : contextRecord?.kind === "mention" && "path" in contextRecord - ? Image.resolveAssetSource( + ? markdownIconAssetUri( markdownFileIconSource(resolveMarkdownFileIcon(contextRecord.path)), - ).uri + ) : undefined, fontSize: props.textStyle.fontSize * 0.8, foreground: props.textStyle.color, @@ -297,10 +297,12 @@ export function NativeMarkdownSelectableText(props: { ? JSON.stringify({ fragment: contextClipboardFragment, ranges }) : ""; const attachAndroidText = useCallback( - (textView: RNText | null) => { + (textView: TextInstance | null) => { if (Platform.OS !== "android" || !containsInlineIcon || !textView) return; const reactTag = findNodeHandle(textView); - if (reactTag !== null) installMarkdownCopySanitizer(reactTag, contextClipboardConfig); + if (typeof reactTag === "number") { + installMarkdownCopySanitizer(reactTag, contextClipboardConfig); + } }, [containsInlineIcon, contextClipboardConfig], ); @@ -358,6 +360,12 @@ export function NativeMarkdownSelectableText(props: { else void Linking.openURL(href); } : undefined; + const fileIconUri = run.fileIcon + ? markdownIconAssetUri(markdownFileIconSource(run.fileIcon)) + : undefined; + const linkIconUri = linkIcon + ? markdownIconAssetUri(markdownLinkIconSource(linkIcon)) + : undefined; return ( ; - ellipsizeMode?: WithDefault; + numberOfLines?: CodegenTypes.Int32; + allowFontScaling?: CodegenTypes.WithDefault; + ellipsizeMode?: CodegenTypes.WithDefault; selectable?: boolean; - onTextLayout?: BubblingEventHandler; + onTextLayout?: CodegenTypes.BubblingEventHandler; /** * Callback fired when the text selection changes. * @@ -48,7 +42,7 @@ interface NativeProps extends ViewProps { * * ``` */ - onSelectionChange?: BubblingEventHandler; + onSelectionChange?: CodegenTypes.BubblingEventHandler; } export default codegenNativeComponent("T3MarkdownText", { diff --git a/apps/mobile/modules/t3-markdown-text/src/T3MarkdownTextRunNativeComponent.ts b/apps/mobile/modules/t3-markdown-text/src/T3MarkdownTextRunNativeComponent.ts index 040e44bc18b5..6c28742256c6 100644 --- a/apps/mobile/modules/t3-markdown-text/src/T3MarkdownTextRunNativeComponent.ts +++ b/apps/mobile/modules/t3-markdown-text/src/T3MarkdownTextRunNativeComponent.ts @@ -1,14 +1,12 @@ -import type { ColorValue, ViewProps } from "react-native"; -import type { - BubblingEventHandler, - Float, - Int32, - WithDefault, -} from "react-native/Libraries/Types/CodegenTypes"; -import codegenNativeComponent from "react-native/Libraries/Utilities/codegenNativeComponent"; +import { + codegenNativeComponent, + type CodegenTypes, + type ColorValue, + type ViewProps, +} from "react-native"; interface TargetedEvent { - target: Int32; + target: CodegenTypes.Int32; } interface ContextMenuActionEvent extends TargetedEvent { @@ -35,21 +33,21 @@ type TextAlign = "auto" | "left" | "right" | "center" | "justify"; interface NativeProps extends ViewProps { text: string; color?: ColorValue; - fontSize?: Float; - fontStyle?: WithDefault; - fontWeight?: WithDefault; + fontSize?: CodegenTypes.Float; + fontStyle?: CodegenTypes.WithDefault; + fontWeight?: CodegenTypes.WithDefault; fontFamily?: string; - letterSpacing?: Float; - lineHeight?: Float; - textDecorationLine?: WithDefault; - textDecorationStyle?: WithDefault; + letterSpacing?: CodegenTypes.Float; + lineHeight?: CodegenTypes.Float; + textDecorationLine?: CodegenTypes.WithDefault; + textDecorationStyle?: CodegenTypes.WithDefault; textDecorationColor?: ColorValue; - textAlign?: WithDefault; - shadowRadius?: WithDefault; + textAlign?: CodegenTypes.WithDefault; + shadowRadius?: CodegenTypes.WithDefault; contextMenuConfig?: string; - onPress?: BubblingEventHandler; - onLongPress?: BubblingEventHandler; - onContextMenuAction?: BubblingEventHandler; + onPress?: CodegenTypes.BubblingEventHandler; + onLongPress?: CodegenTypes.BubblingEventHandler; + onContextMenuAction?: CodegenTypes.BubblingEventHandler; } export default codegenNativeComponent("T3MarkdownTextRun", { diff --git a/apps/mobile/modules/t3-markdown-text/src/markdownFileIcons.ts b/apps/mobile/modules/t3-markdown-text/src/markdownFileIcons.ts index 94b08c1de7ee..99c902727dfe 100644 --- a/apps/mobile/modules/t3-markdown-text/src/markdownFileIcons.ts +++ b/apps/mobile/modules/t3-markdown-text/src/markdownFileIcons.ts @@ -1,4 +1,4 @@ -import type { ImageSourcePropType } from "react-native"; +import { Image, type ImageSourcePropType } from "react-native"; import type { MarkdownFileIcon } from "./markdownLinks"; import { MARKDOWN_FILE_ICON_SOURCES } from "./markdownFileIcons.generated"; @@ -6,3 +6,12 @@ import { MARKDOWN_FILE_ICON_SOURCES } from "./markdownFileIcons.generated"; export function markdownFileIconSource(icon: MarkdownFileIcon): ImageSourcePropType { return MARKDOWN_FILE_ICON_SOURCES[icon]; } + +/** + * Bundled icon URI handed to native views that draw the icon themselves. The + * sources are static requires, so this only comes back undefined when the + * bundler dropped the asset; callers treat a missing icon as "no icon". + */ +export function markdownIconAssetUri(source: ImageSourcePropType): string | undefined { + return Image.resolveAssetSource(source)?.uri; +} diff --git a/apps/mobile/package.json b/apps/mobile/package.json index fb3eee190cd1..ae52098e59dd 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -49,7 +49,8 @@ "@clerk/expo": "catalog:", "@effect/atom-react": "catalog:", "@expo-google-fonts/dm-sans": "^0.4.2", - "@expo/ui": "~57.0.14", + "@expo/metro-runtime": "~58.0.9", + "@expo/ui": "~58.0.9", "@legendapp/list": "catalog:", "@material/material-color-utilities": "0.3.0", "@noble/curves": "catalog:", @@ -73,56 +74,56 @@ "clsx": "^2.1.1", "diff": "8.0.3", "effect": "catalog:", - "expo": "~57.0.18", - "expo-asset": "~57.0.15", - "expo-audio": "57.0.4", - "expo-auth-session": "~57.0.10", - "expo-blur": "~57.0.2", - "expo-build-properties": "~57.0.15", - "expo-camera": "~57.0.4", - "expo-clipboard": "~57.0.1", - "expo-constants": "~57.0.16", - "expo-crypto": "~57.0.2", - "expo-dev-client": "~57.0.16", - "expo-device": "~57.0.1", - "expo-document-picker": "~57.0.1", - "expo-file-system": "~57.0.6", - "expo-font": "~57.0.2", - "expo-glass-effect": "~57.0.1", - "expo-haptics": "~57.0.2", - "expo-image": "~57.0.3", - "expo-image-manipulator": "~57.0.17", - "expo-image-picker": "~57.0.14", - "expo-keep-awake": "~57.0.2", - "expo-linking": "~57.0.8", - "expo-network": "~57.0.1", - "expo-notifications": "57.0.15", + "expo": "58.0.0", + "expo-asset": "~58.0.9", + "expo-audio": "58.0.3", + "expo-auth-session": "~58.0.6", + "expo-blur": "58.0.2", + "expo-build-properties": "~58.0.9", + "expo-camera": "~58.0.5", + "expo-clipboard": "~58.0.2", + "expo-constants": "~58.0.9", + "expo-crypto": "~58.0.3", + "expo-dev-client": "~58.0.9", + "expo-device": "~58.0.3", + "expo-document-picker": "~58.0.3", + "expo-file-system": "~58.0.4", + "expo-font": "~58.0.4", + "expo-glass-effect": "58.0.3", + "expo-haptics": "~58.0.3", + "expo-image": "~58.0.8", + "expo-image-manipulator": "~58.0.10", + "expo-image-picker": "~58.0.9", + "expo-keep-awake": "~58.0.2", + "expo-linking": "~58.0.9", + "expo-network": "~58.0.2", + "expo-notifications": "~58.0.9", "expo-paste-input": "^0.1.15", "expo-quick-actions": "^6.0.2", - "expo-secure-store": "~57.0.2", - "expo-sharing": "57.0.17", - "expo-splash-screen": "~57.0.8", - "expo-sqlite": "~57.0.2", - "expo-symbols": "~57.0.2", - "expo-updates": "~57.0.19", - "expo-video": "~57.0.3", - "expo-web-browser": "~57.0.2", - "expo-widgets": "57.0.15", - "react": "19.2.3", - "react-dom": "19.2.3", - "react-native": "0.86.3", - "react-native-gesture-handler": "~2.32.0", + "expo-secure-store": "~58.0.1", + "expo-sharing": "58.0.12", + "expo-splash-screen": "~58.0.2", + "expo-sqlite": "~58.0.7", + "expo-symbols": "~58.0.3", + "expo-updates": "~58.0.11", + "expo-video": "~58.0.5", + "expo-web-browser": "~58.0.3", + "expo-widgets": "58.0.9", + "react": "19.3.0", + "react-dom": "19.3.0", + "react-native": "0.88.0-rc.3", + "react-native-gesture-handler": "~3.2.1", "react-native-image-viewing": "^0.2.2", - "react-native-keyboard-controller": "1.21.13", + "react-native-keyboard-controller": "1.22.4", "react-native-nitro-markdown": "^0.5.0", "react-native-nitro-modules": "0.35.9", - "react-native-reanimated": "4.5.5", - "react-native-safe-area-context": "~5.7.0", - "react-native-screens": "~4.26.0", + "react-native-reanimated": "4.7.0", + "react-native-safe-area-context": "~5.9.1", + "react-native-screens": "~4.28.0", "react-native-shiki-engine": "^0.3.12", - "react-native-svg": "15.15.4", - "react-native-webview": "^13.16.1", - "react-native-worklets": "0.11.4", + "react-native-svg": "15.15.5", + "react-native-webview": "14.0.1", + "react-native-worklets": "0.13.0", "shiki": "4.2.0", "tailwind-merge": "^3.5.0", "uniwind": "1.11.0" @@ -130,9 +131,9 @@ "devDependencies": { "@effect/vitest": "catalog:", "@pierre/trees": "1.0.0-beta.4", - "@types/react": "~19.2.0", + "@types/react": "~19.3.0", "@types/react-dom": "~19.2.3", - "babel-preset-expo": "~57.0.9", + "babel-preset-expo": "~58.0.6", "tailwindcss": "^4.0.0", "typescript": "catalog:" }, diff --git a/apps/mobile/plugins/withIosSceneLifecycle.cjs b/apps/mobile/plugins/withIosSceneLifecycle.cjs deleted file mode 100644 index c0d7f02ece32..000000000000 --- a/apps/mobile/plugins/withIosSceneLifecycle.cjs +++ /dev/null @@ -1,123 +0,0 @@ -const { withAppDelegate, withInfoPlist } = require("expo/config-plugins"); - -const SCENE_DELEGATE = ` - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene( - _ scene: UIScene, - willConnectTo session: UISceneSession, - options connectionOptions: UIScene.ConnectionOptions - ) { - guard - let windowScene = scene as? UIWindowScene, - let appDelegate = UIApplication.shared.delegate as? AppDelegate - else { - return - } - - let appWindow: UIWindow - if let existingWindow = appDelegate.window { - appWindow = existingWindow - } else { - appWindow = UIWindow(windowScene: windowScene) - appDelegate.window = appWindow - appDelegate.reactNativeFactory?.startReactNative( - withModuleName: "main", - in: appWindow, - launchOptions: appDelegate.sceneLaunchOptions) - appDelegate.sceneLaunchOptions = nil - } - - window = appWindow - appWindow.windowScene = windowScene - appWindow.makeKeyAndVisible() - - if let url = connectionOptions.urlContexts.first?.url { - _ = appDelegate.application(UIApplication.shared, open: url, options: [:]) - } - - if let userActivity = connectionOptions.userActivities.first { - _ = appDelegate.application( - UIApplication.shared, - continue: userActivity, - restorationHandler: { _ in }) - } - } - - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - guard - let url = URLContexts.first?.url, - let appDelegate = UIApplication.shared.delegate as? AppDelegate - else { - return - } - - _ = appDelegate.application(UIApplication.shared, open: url, options: [:]) - } - - func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { - return - } - - _ = appDelegate.application( - UIApplication.shared, - continue: userActivity, - restorationHandler: { _ in }) - } -}`; - -module.exports = function withIosSceneLifecycle(config) { - config = withInfoPlist(config, (nextConfig) => { - nextConfig.modResults.UIApplicationSceneManifest = { - UIApplicationSupportsMultipleScenes: false, - UISceneConfigurations: { - UIWindowSceneSessionRoleApplication: [ - { - UISceneConfigurationName: "Default Configuration", - UISceneDelegateClassName: "$(PRODUCT_MODULE_NAME).SceneDelegate", - }, - ], - }, - }; - - return nextConfig; - }); - - return withAppDelegate(config, (nextConfig) => { - if (nextConfig.modResults.language !== "swift") { - throw new Error("The iOS scene lifecycle plugin requires a Swift AppDelegate."); - } - - // Creating the window before a scene exists leaves iOS share scenes with - // incorrect geometry, even if windowScene is assigned afterward. - const startup = - /window = UIWindow\(frame: UIScreen\.main\.bounds\)\s+factory\.startReactNative\(\s+withModuleName: "main",\s+in: window,\s+launchOptions: launchOptions\)/; - if (startup.test(nextConfig.modResults.contents)) { - nextConfig.modResults.contents = nextConfig.modResults.contents.replace( - startup, - "sceneLaunchOptions = launchOptions", - ); - } else if (!nextConfig.modResults.contents.includes("sceneLaunchOptions = launchOptions")) { - throw new Error("Could not move React Native startup into the iOS scene lifecycle."); - } - if (!nextConfig.modResults.contents.includes("var sceneLaunchOptions:")) { - nextConfig.modResults.contents = nextConfig.modResults.contents.replace( - "var window: UIWindow?", - "var window: UIWindow?\n var sceneLaunchOptions: [UIApplication.LaunchOptionsKey: Any]?", - ); - } - if (!nextConfig.modResults.contents.includes("class SceneDelegate:")) { - nextConfig.modResults.contents += SCENE_DELEGATE; - } else { - nextConfig.modResults.contents = nextConfig.modResults.contents.replace( - "in: appWindow,\n launchOptions: nil)", - "in: appWindow,\n launchOptions: appDelegate.sceneLaunchOptions)\n appDelegate.sceneLaunchOptions = nil", - ); - } - - return nextConfig; - }); -}; diff --git a/apps/mobile/plugins/withIosSceneLifecycle.test.mjs b/apps/mobile/plugins/withIosSceneLifecycle.test.mjs deleted file mode 100644 index 34af7ab27fa2..000000000000 --- a/apps/mobile/plugins/withIosSceneLifecycle.test.mjs +++ /dev/null @@ -1,58 +0,0 @@ -import { describe, expect, it } from "vitest"; -import withIosSceneLifecycle from "./withIosSceneLifecycle.cjs"; - -const appDelegate = `class AppDelegate: ExpoAppDelegate { - var window: UIWindow? - func application() { - window = UIWindow(frame: UIScreen.main.bounds) - factory.startReactNative( - withModuleName: "main", - in: window, - launchOptions: launchOptions) - } -}`; - -async function transform(contents) { - const config = withIosSceneLifecycle({ name: "Test", slug: "test" }); - const result = await config.mods.ios.appDelegate({ - ...config, - modRequest: { platform: "ios", modName: "appDelegate", introspect: false }, - modResults: { language: "swift", contents }, - }); - return result.modResults.contents; -} - -describe("iOS scene lifecycle generation", () => { - it("creates the window in the scene before starting React Native and retains launch options", async () => { - const result = await transform(appDelegate); - const [startup, scene] = result.split("class SceneDelegate:"); - expect(startup).not.toContain("UIWindow(frame:"); - expect(startup).not.toContain("startReactNative("); - expect(startup).toContain("sceneLaunchOptions = launchOptions"); - expect(scene.indexOf("UIWindow(windowScene: windowScene)")).toBeLessThan( - scene.indexOf("startReactNative("), - ); - expect(scene).toContain("launchOptions: appDelegate.sceneLaunchOptions)"); - expect(scene).toContain("appDelegate.sceneLaunchOptions = nil"); - }); - - it("does not duplicate startup or scene code on subsequent prebuilds", async () => { - const generated = await transform(appDelegate); - expect(await transform(generated)).toBe(generated); - }); - - it("updates the previously generated scene delegate", async () => { - const generated = await transform(appDelegate); - const oldScene = generated - .slice(generated.indexOf("class SceneDelegate:")) - .replace("launchOptions: appDelegate.sceneLaunchOptions)", "launchOptions: nil)") - .replace(" appDelegate.sceneLaunchOptions = nil\n", ""); - expect(await transform(`${appDelegate}\n\n${oldScene}`)).toBe(generated); - }); - - it("fails visibly when the Expo startup template changes", async () => { - await expect(transform("class AppDelegate: ExpoAppDelegate {}")).rejects.toThrow( - "Could not move React Native startup", - ); - }); -}); diff --git a/apps/mobile/src/App.tsx b/apps/mobile/src/App.tsx index 34a742f8f11b..001c9d597cc8 100644 --- a/apps/mobile/src/App.tsx +++ b/apps/mobile/src/App.tsx @@ -76,10 +76,7 @@ function AppContent() { - + {/* The navigation theme drives the NATIVE header appearance: native-stack forwards `dark` as the nav bar's overrideUserInterfaceStyle. Without this, React Navigation defaults to its light theme and every native diff --git a/apps/mobile/src/Stack.tsx b/apps/mobile/src/Stack.tsx index 4baeadb94238..417473ba20e8 100644 --- a/apps/mobile/src/Stack.tsx +++ b/apps/mobile/src/Stack.tsx @@ -520,7 +520,12 @@ function RootStackLayout(props: { const navigation = useNavigation(); const { pendingShare } = useIncomingShare(); const sharePresentationRef = useRef(EMPTY_INCOMING_SHARE_PRESENTATION_STATE); - useAgentNotificationNavigation(); + // Keyboard commands follow the top route; notification suppression follows + // the thread beneath overlay sheets. + const path = getPathFromState(props.state, navigationPathConfig); + const pathname = path.startsWith("/") ? path : `/${path}`; + const workspaceLocation = workspaceLocationFromState(props.state); + useAgentNotificationNavigation(workspaceLocation.pathname); // Presents the T3 Connect onboarding sheet after an in-session sign-in. useConnectOnboardingNavigation(); // Launcher app shortcuts: routes shortcut taps and tracks opened threads. @@ -540,11 +545,6 @@ function RootStackLayout(props: { params: { incomingShareId: transition.shareIdToPresent }, }); }, [navigation, pendingShare, props.state]); - // Full pathname (sheets included) for keyboard-command scoping; the - // workspace layout only reacts to the underlying non-overlay route. - const path = getPathFromState(props.state, navigationPathConfig); - const pathname = path.startsWith("/") ? path : `/${path}`; - const workspaceLocation = workspaceLocationFromState(props.state); return ( diff --git a/apps/mobile/src/components/AndroidAnchoredMenu.tsx b/apps/mobile/src/components/AndroidAnchoredMenu.tsx index 4c465a9f9ef4..5dccade1c9ae 100644 --- a/apps/mobile/src/components/AndroidAnchoredMenu.tsx +++ b/apps/mobile/src/components/AndroidAnchoredMenu.tsx @@ -1,7 +1,7 @@ import type { MenuAction, MenuComponentProps } from "@react-native-menu/menu"; import type { ReactNode } from "react"; import { useCallback, useEffect, useRef, useState } from "react"; -import type { StyleProp, ViewStyle } from "react-native"; +import type { StyleProp, ViewInstance, ViewStyle } from "react-native"; import { BackHandler, Pressable, ScrollView, View } from "react-native"; import { useKeyboardState } from "react-native-keyboard-controller"; import Animated, { FadeIn } from "react-native-reanimated"; @@ -73,8 +73,8 @@ export function AndroidAnchoredMenu(props: AndroidAnchoredMenuProps) { overlay === null ? desiredMenuWidth : Math.min(desiredMenuWidth, Math.max(0, overlay.width - 2 * SCREEN_MARGIN)); - const anchorRef = useRef(null); - const overlayRef = useRef(null); + const anchorRef = useRef(null); + const overlayRef = useRef(null); const keyboardVisible = useKeyboardState((state) => state.isVisible); const keyboardHeight = useKeyboardState((state) => state.height); diff --git a/apps/mobile/src/components/AppText.tsx b/apps/mobile/src/components/AppText.tsx index 6f96f4246953..7423ff678549 100644 --- a/apps/mobile/src/components/AppText.tsx +++ b/apps/mobile/src/components/AppText.tsx @@ -2,6 +2,7 @@ import { Platform, Text as RNText, TextInput as RNTextInput, + type TextInputInstance, type TextInputProps as RNTextInputProps, type TextProps as RNTextProps, } from "react-native"; @@ -26,7 +27,7 @@ export function AppText({ className, ...props }: AppTextProps) { export type AppTextInputProps = Omit & { readonly className?: string; - readonly ref?: React.Ref; + readonly ref?: React.Ref; }; /** diff --git a/apps/mobile/src/components/ComposerAttachmentStrip.tsx b/apps/mobile/src/components/ComposerAttachmentStrip.tsx index 04382839c909..7e988f1075e3 100644 --- a/apps/mobile/src/components/ComposerAttachmentStrip.tsx +++ b/apps/mobile/src/components/ComposerAttachmentStrip.tsx @@ -127,7 +127,7 @@ async function materializeDataUrlPreview(id: string, dataUrl: string): Promise; + readonly ref?: Ref; readonly children: ReactNode; readonly glassEffectStyle?: "clear" | "regular" | "none"; readonly tintColor?: ColorValue; diff --git a/apps/mobile/src/components/LoadingScreen.tsx b/apps/mobile/src/components/LoadingScreen.tsx index 456a347d365d..351f828d3be2 100644 --- a/apps/mobile/src/components/LoadingScreen.tsx +++ b/apps/mobile/src/components/LoadingScreen.tsx @@ -15,7 +15,7 @@ export function LoadingScreen(props: { return ( - + {messagePlacement === "above-spinner" ? ( diff --git a/apps/mobile/src/components/MaterialSearchField.tsx b/apps/mobile/src/components/MaterialSearchField.tsx index 3609430a6e1a..639249313bfd 100644 --- a/apps/mobile/src/components/MaterialSearchField.tsx +++ b/apps/mobile/src/components/MaterialSearchField.tsx @@ -1,5 +1,5 @@ import type { RefObject } from "react"; -import { Pressable, TextInput, View } from "react-native"; +import { Pressable, TextInput, type TextInputInstance, View } from "react-native"; import { SymbolView } from "./AppSymbol"; import { useAndroidControlSizing } from "./useAndroidControlSizing"; @@ -12,7 +12,7 @@ export function MaterialSearchField({ value, onChangeText, }: { - readonly inputRef: RefObject; + readonly inputRef: RefObject; readonly accessibilityLabel: string; readonly clearAccessibilityLabel: string; readonly placeholder: string; diff --git a/apps/mobile/src/components/ScreenHeader.android.tsx b/apps/mobile/src/components/ScreenHeader.android.tsx index 1d3232fd1641..333afbce7ccc 100644 --- a/apps/mobile/src/components/ScreenHeader.android.tsx +++ b/apps/mobile/src/components/ScreenHeader.android.tsx @@ -1,5 +1,12 @@ import { useCallback, useEffect, useRef, useState } from "react"; -import { BackHandler, Keyboard, Pressable, TextInput, View } from "react-native"; +import { + BackHandler, + Keyboard, + Pressable, + TextInput, + type TextInputInstance, + View, +} from "react-native"; import { useMaterialToolbarLayout } from "./useMaterialToolbarLayout"; import { NativeStackScreenOptions } from "../native/StackHeader"; import { AndroidWorkspaceSidebarButton } from "../features/layout/workspace-sidebar-toolbar"; @@ -18,7 +25,7 @@ export function ScreenHeader(props: ScreenHeaderProps) { const { paddingTop, paddingBottom } = useMaterialToolbarLayout(); const { scale, buttonSize, iconSize, smallIconSize } = useAndroidControlSizing(); const { themeVariables } = useAppearancePreferences(); - const inputRef = useRef(null); + const inputRef = useRef(null); const [searchOpen, setSearchOpen] = useState(false); const searching = search !== undefined && (searchOpen || search.value.length > 0); const onSearchChange = search?.onChangeText; diff --git a/apps/mobile/src/connection/background-activity.ts b/apps/mobile/src/connection/background-activity.ts index 3364eed3c2d1..6ecc8d81f464 100644 --- a/apps/mobile/src/connection/background-activity.ts +++ b/apps/mobile/src/connection/background-activity.ts @@ -14,7 +14,7 @@ import * as Queue from "effect/Queue"; import * as Schedule from "effect/Schedule"; import * as Stream from "effect/Stream"; import * as SubscriptionRef from "effect/SubscriptionRef"; -import { AppState, type AppStateStatus } from "react-native"; +import { AppState } from "react-native"; import * as MobileStorage from "../persistence/mobile-storage"; import { @@ -27,8 +27,10 @@ const REPORT_INTERVAL_MS = 25_000; const LEASE_TTL_MS = 45_000; const BASELINE_SCOPES: ReadonlyArray = [{ type: "provider-status" }]; +// `AppState.currentState` is a loosely typed string that can be unset before +// the first change event; anything outside the known states reports as unknown. function normalizeAppState( - state: AppStateStatus, + state: string | null | undefined, ): NonNullable { if (state === "active" || state === "inactive" || state === "background") return state; return "unknown"; diff --git a/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.test.ts b/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.test.ts new file mode 100644 index 000000000000..a76391732239 --- /dev/null +++ b/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.test.ts @@ -0,0 +1,61 @@ +import type { Notification } from "expo-notifications"; +import { describe, expect, it } from "vite-plus/test"; + +import { foregroundNotificationBehavior } from "./foregroundNotificationBehavior"; +import { threadDeepLinkOnScreen } from "./notificationPayload"; + +function notificationWithData(data: Record): Notification { + return { + date: 0, + request: { identifier: "notification-1", content: { data }, trigger: null }, + } as unknown as Notification; +} + +describe("threadDeepLinkOnScreen", () => { + it("maps a thread route and its nested screens to the thread deep link", () => { + expect(threadDeepLinkOnScreen("/threads/env-1/thread-1")).toBe("/threads/env-1/thread-1"); + expect(threadDeepLinkOnScreen("/threads/env-1/thread-1/files/src")).toBe( + "/threads/env-1/thread-1", + ); + }); + + it("returns null outside a thread", () => { + expect(threadDeepLinkOnScreen("/")).toBeNull(); + expect(threadDeepLinkOnScreen("/settings")).toBeNull(); + expect(threadDeepLinkOnScreen("/threads/env-1")).toBeNull(); + }); +}); + +describe("foregroundNotificationBehavior", () => { + it("suppresses a notification for the thread already on screen", () => { + const behavior = foregroundNotificationBehavior( + notificationWithData({ environmentId: "env-1", threadId: "thread-1" }), + "/threads/env-1/thread-1", + ); + expect(behavior.shouldShowBanner).toBe(false); + expect(behavior.shouldShowList).toBe(false); + expect(behavior.shouldPlaySound).toBe(false); + }); + + it("shows a notification for another thread", () => { + const behavior = foregroundNotificationBehavior( + notificationWithData({ deepLink: "/threads/env-1/thread-2" }), + "/threads/env-1/thread-1", + ); + expect(behavior.shouldShowBanner).toBe(true); + expect(behavior.shouldShowList).toBe(true); + }); + + it("shows a notification when no thread is open or the payload has no target", () => { + expect( + foregroundNotificationBehavior( + notificationWithData({ environmentId: "env-1", threadId: "thread-1" }), + null, + ).shouldShowBanner, + ).toBe(true); + expect( + foregroundNotificationBehavior(notificationWithData({}), "/threads/env-1/thread-1") + .shouldShowBanner, + ).toBe(true); + }); +}); diff --git a/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.ts b/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.ts new file mode 100644 index 000000000000..9ea77169dfea --- /dev/null +++ b/apps/mobile/src/features/agent-awareness/foregroundNotificationBehavior.ts @@ -0,0 +1,35 @@ +import type { Notification, NotificationBehavior } from "expo-notifications"; + +import { extractAgentNotificationDeepLink } from "./notificationPayload"; + +const SHOW: NotificationBehavior = { + shouldShowBanner: true, + shouldShowList: true, + shouldPlaySound: true, + shouldSetBadge: false, +}; + +const SUPPRESS: NotificationBehavior = { + shouldShowBanner: false, + shouldShowList: false, + shouldPlaySound: false, + shouldSetBadge: false, +}; + +/** + * Decides how a notification that arrives while the app is open is presented. + * A notification for the thread already on screen is redundant with the live + * feed, so it stays silent; everything else banners like it would in the + * background. `deepLinkOnScreen` is the normalized `/threads/:env/:thread` + * path of the current route, or null when no thread is open. + */ +export function foregroundNotificationBehavior( + notification: Notification, + deepLinkOnScreen: string | null, +): NotificationBehavior { + const target = extractAgentNotificationDeepLink({ notification }); + if (target !== null && target === deepLinkOnScreen) { + return SUPPRESS; + } + return SHOW; +} diff --git a/apps/mobile/src/features/agent-awareness/notificationNavigation.ts b/apps/mobile/src/features/agent-awareness/notificationNavigation.ts index e9ca9246b9a9..ff65371ba3b6 100644 --- a/apps/mobile/src/features/agent-awareness/notificationNavigation.ts +++ b/apps/mobile/src/features/agent-awareness/notificationNavigation.ts @@ -2,12 +2,27 @@ import { useEffect, useRef } from "react"; import * as Notifications from "expo-notifications"; import { useLinkTo } from "@react-navigation/native"; -import { routeAgentNotificationResponseOnce } from "./notificationPayload"; +import { foregroundNotificationBehavior } from "./foregroundNotificationBehavior"; +import { routeAgentNotificationResponseOnce, threadDeepLinkOnScreen } from "./notificationPayload"; import { consumeLastAgentNotificationResponse } from "./notificationResponseConsumer"; -export function useAgentNotificationNavigation(): void { +export function useAgentNotificationNavigation(pathname: string): void { const linkTo = useLinkTo(); const handledResponseIds = useRef(new Set()); + // Read through a ref so the native handler registered once below sees the + // current route without re-registering on every navigation. + const deepLinkOnScreen = useRef(null); + deepLinkOnScreen.current = threadDeepLinkOnScreen(pathname); + + useEffect(() => { + Notifications.setNotificationHandler({ + handleNotification: (notification) => + Promise.resolve(foregroundNotificationBehavior(notification, deepLinkOnScreen.current)), + }); + return () => { + Notifications.setNotificationHandler(null); + }; + }, []); useEffect(() => { const handleResponse = (response: Notifications.NotificationResponse): void => { diff --git a/apps/mobile/src/features/agent-awareness/notificationPayload.ts b/apps/mobile/src/features/agent-awareness/notificationPayload.ts index dc72e3d1bd27..e568ca8b6cd4 100644 --- a/apps/mobile/src/features/agent-awareness/notificationPayload.ts +++ b/apps/mobile/src/features/agent-awareness/notificationPayload.ts @@ -69,6 +69,19 @@ function normalizeThreadDeepLink(value: string): string | null { } } +/** + * The deep link a notification would have to carry to target the thread the + * given route is showing, including its nested screens such as the file + * inspector. Null when the route is not inside a thread. + */ +export function threadDeepLinkOnScreen(pathname: string): string | null { + const match = /^\/threads\/([^/]+)\/([^/]+)(?:\/|$)/.exec(pathname); + if (!match?.[1] || !match[2]) { + return null; + } + return `/threads/${match[1]}/${match[2]}`; +} + export function extractAgentNotificationDeepLink(response: unknown): string | null { const data = dataFromNotificationResponse(response); const deepLink = data?.deepLink; diff --git a/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx b/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx index b786f9f4066c..374d17ac4762 100644 --- a/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx +++ b/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx @@ -20,7 +20,7 @@ import { useWindowDimensions, View, } from "react-native"; -import { Gesture, GestureDetector } from "react-native-gesture-handler"; +import { GestureDetector, useNativeGesture } from "react-native-gesture-handler"; import type { SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable"; import { AppText as Text } from "../../components/AppText"; @@ -185,9 +185,7 @@ function ArchivedThreadRow(props: { readonly onDelete: () => void; readonly onSwipeableClose: (methods: SwipeableMethods) => void; readonly onSwipeableWillOpen: (methods: SwipeableMethods) => void; - readonly simultaneousSwipeGesture?: ComponentProps< - typeof ThreadSwipeable - >["simultaneousWithExternalGesture"]; + readonly simultaneousSwipeGesture?: ComponentProps["simultaneousWith"]; readonly onUnarchive: () => void; readonly thread: EnvironmentThreadShell; }) { @@ -221,7 +219,7 @@ function ArchivedThreadRow(props: { label: "Unarchive", onPress: props.onUnarchive, }} - simultaneousWithExternalGesture={props.simultaneousSwipeGesture} + simultaneousWith={props.simultaneousSwipeGesture} threadTitle={props.thread.title} > {() => ( @@ -303,7 +301,7 @@ export function ArchivedThreadsScreen(props: { }) { const { onDeleteThread, onUnarchiveThread } = props; const openSwipeableRef = useRef(null); - const archiveScrollGesture = useMemo(() => Gesture.Native(), []); + const archiveScrollGesture = useNativeGesture(); const environmentLabelsById = useMemo( () => new Map( diff --git a/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx b/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx index d362b78a9360..dd6364f23d4f 100644 --- a/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx +++ b/apps/mobile/src/features/connection/CloudEnvironmentRows.tsx @@ -13,13 +13,7 @@ import { } from "@t3tools/contracts"; import { useAtomValue } from "@effect/atom-react"; import { useCallback, useState } from "react"; -import { - ActivityIndicator, - Pressable, - type NativeSyntheticEvent, - type TextLayoutEventData, - View, -} from "react-native"; +import { ActivityIndicator, Pressable, type TextLayoutEvent, View } from "react-native"; import { AppText as Text } from "../../components/AppText"; import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSymbol"; @@ -334,7 +328,7 @@ function CloudEnvironmentRowShell(props: { const isErrorExpanded = errorCanExpand && props.errorExpanded; const StatusContainer = errorCanExpand ? Pressable : View; const onMeasuredErrorTextLayout = useCallback( - (event: NativeSyntheticEvent) => { + (event: TextLayoutEvent) => { if (!props.connectionError) { return; } diff --git a/apps/mobile/src/features/devices/DeviceStreamWebView.tsx b/apps/mobile/src/features/devices/DeviceStreamWebView.tsx index 423fdb1c84a0..c8831c595202 100644 --- a/apps/mobile/src/features/devices/DeviceStreamWebView.tsx +++ b/apps/mobile/src/features/devices/DeviceStreamWebView.tsx @@ -89,7 +89,7 @@ function DeviceStreamDocumentView({ readonly onStreaming: () => void; readonly onRecoverProcess: () => boolean; }) { - const webView = useRef(null); + const webView = useRef>(null); const active = useRef(true); const failed = useRef(false); const [status, setStatus] = useState("connecting"); @@ -148,7 +148,7 @@ function DeviceStreamDocumentView({ }; return ( - ref={webView} source={source} originWhitelist={["*"]} diff --git a/apps/mobile/src/features/files/MaterialFilesHeader.tsx b/apps/mobile/src/features/files/MaterialFilesHeader.tsx index c652ab67d377..17bd76b6ce3b 100644 --- a/apps/mobile/src/features/files/MaterialFilesHeader.tsx +++ b/apps/mobile/src/features/files/MaterialFilesHeader.tsx @@ -1,5 +1,5 @@ import { useCallback, useEffect, useRef, useState, type ReactNode } from "react"; -import { BackHandler, Keyboard, type TextInput, View } from "react-native"; +import { BackHandler, Keyboard, type TextInputInstance, View } from "react-native"; import { AndroidHeaderIconButton, AndroidScreenHeader } from "../../components/AndroidScreenHeader"; import { AndroidAnchoredMenu } from "../../components/AndroidAnchoredMenu"; @@ -16,7 +16,7 @@ export function MaterialFilesHeader(props: { readonly leading?: ReactNode; }) { const { paddingTop, paddingBottom } = useMaterialToolbarLayout(); - const searchRef = useRef(null); + const searchRef = useRef(null); const [searchOpen, setSearchOpen] = useState(false); const searching = searchOpen || props.searchQuery.length > 0; const { onSearchQueryChange } = props; diff --git a/apps/mobile/src/features/home/HomeScreen.tsx b/apps/mobile/src/features/home/HomeScreen.tsx index 75be079f0de8..c54f1c12bf58 100644 --- a/apps/mobile/src/features/home/HomeScreen.tsx +++ b/apps/mobile/src/features/home/HomeScreen.tsx @@ -309,8 +309,8 @@ export function HomeScreen(props: HomeScreenProps) { (event: GestureResponderEvent, started: boolean) => { const { changedTouches, touches } = event.nativeEvent; swipeRowActivation.trackTouches( - started ? changedTouches.map((touch) => touch.identifier) : [], - touches.map((touch) => touch.identifier), + started ? changedTouches.map((touch) => String(touch.identifier)) : [], + touches.map((touch) => String(touch.identifier)), ); }, [swipeRowActivation], @@ -945,7 +945,7 @@ export function HomeScreen(props: HomeScreenProps) { ); } - const listHeader = Platform.OS === "ios" ? null : ; + const listHeader = Platform.OS === "ios" ? undefined : ; // Project scoping lives in the header filter menu (no inline chip row on // mobile — the menu is the one filter surface). @@ -954,7 +954,7 @@ export function HomeScreen(props: HomeScreenProps) { // Use the v2 project scope for its empty state. Snoozed threads need no // special empty state: their shelf header is a list row even while collapsed. const v2ListEmpty = - hasSearchQuery && threadSearch.isPending ? null : hasSearchQuery ? ( + hasSearchQuery && threadSearch.isPending ? undefined : hasSearchQuery ? ( (null); + const searchRef = useRef(null); const [searchOpen, setSearchOpen] = useState(false); const searching = searchOpen || props.searchQuery.length > 0; const openSearch = useCallback(() => { diff --git a/apps/mobile/src/features/home/thread-swipe-actions.tsx b/apps/mobile/src/features/home/thread-swipe-actions.tsx index e62935c28861..1d61cd3a0af2 100644 --- a/apps/mobile/src/features/home/thread-swipe-actions.tsx +++ b/apps/mobile/src/features/home/thread-swipe-actions.tsx @@ -266,9 +266,7 @@ interface ThreadSwipeableProps { readonly resetKey?: string; /** Paints the row without swipe machinery; see swipe-row-activation. */ readonly dormant?: boolean; - readonly simultaneousWithExternalGesture?: ComponentProps< - typeof ReanimatedSwipeable - >["simultaneousWithExternalGesture"]; + readonly simultaneousWith?: ComponentProps["simultaneousWith"]; readonly threadTitle: string; } @@ -433,7 +431,7 @@ function ThreadSwipeableRow(props: ThreadSwipeableProps) { animationOptions={THREAD_SWIPE_SPRING} childrenContainerStyle={{ backgroundColor: props.backgroundColor }} containerStyle={[{ backgroundColor: props.backgroundColor }, props.containerStyle]} - dragOffsetFromRightEdge={8} + dragOffsetFromRight={-8} enabled={!isDismissing && props.enabled !== false && gateEnabled} enableTrackpadTwoFingerGesture={props.enableTrackpadSwipe ?? true} // Fail the swipe once the pan is vertically dominant (patched-in RNGH @@ -497,7 +495,7 @@ function ThreadSwipeableRow(props: ThreadSwipeableProps) { )} rightThreshold={actionsWidth * 0.42} - simultaneousWithExternalGesture={props.simultaneousWithExternalGesture} + simultaneousWith={props.simultaneousWith} > {props.children(close)} diff --git a/apps/mobile/src/features/keyboard/CommandPalette.tsx b/apps/mobile/src/features/keyboard/CommandPalette.tsx index 32344ef3fdac..e7d7b695b150 100644 --- a/apps/mobile/src/features/keyboard/CommandPalette.tsx +++ b/apps/mobile/src/features/keyboard/CommandPalette.tsx @@ -12,6 +12,7 @@ import { TextInput, useWindowDimensions, View, + type TextInputInstance, } from "react-native"; import { GestureHandlerRootView } from "react-native-gesture-handler"; @@ -151,7 +152,7 @@ export function CommandPalette(props: { const [visible, setVisible] = useState(true); const pendingAction = useRef<(() => void) | null>(null); const closing = useRef(false); - const inputRef = useRef(null); + const inputRef = useRef(null); const listRef = useRef>(null); const { width, height } = useWindowDimensions(); const searchEnvironmentIds = useMemo( diff --git a/apps/mobile/src/features/sharing/incoming-share-storage.ts b/apps/mobile/src/features/sharing/incoming-share-storage.ts index ce6d5ed0c5cd..763da41cba8c 100644 --- a/apps/mobile/src/features/sharing/incoming-share-storage.ts +++ b/apps/mobile/src/features/sharing/incoming-share-storage.ts @@ -68,7 +68,7 @@ export async function writeIncomingShareDraft(draft: IncomingShareDraft): Promis if (!file.exists) { file.create({ intermediates: true, overwrite: true }); } - file.write(JSON.stringify(draft)); + await file.write(JSON.stringify(draft)); } catch (cause) { throw new IncomingShareStorageError({ operation: "write", shareId: draft.id, cause }); } diff --git a/apps/mobile/src/features/terminal/NativeTerminalSurface.tsx b/apps/mobile/src/features/terminal/NativeTerminalSurface.tsx index e7beb0de54f8..328617bb7172 100644 --- a/apps/mobile/src/features/terminal/NativeTerminalSurface.tsx +++ b/apps/mobile/src/features/terminal/NativeTerminalSurface.tsx @@ -6,6 +6,7 @@ import { View, type LayoutChangeEvent, type NativeSyntheticEvent, + type TextInputInstance, type ViewProps, } from "react-native"; @@ -61,7 +62,7 @@ function estimateGridSize(input: { const FallbackTerminalSurface = memo(function FallbackTerminalSurface(props: TerminalSurfaceProps) { const fontSize = props.fontSize ?? MOBILE_TYPOGRAPHY.label.fontSize; - const inputRef = useRef(null); + const inputRef = useRef(null); const { themeAppearance, themeId } = useAppearancePreferences(); const theme = props.theme ?? getMobileTerminalTheme(themeId, themeAppearance); const statusLabel = props.isRunning diff --git a/apps/mobile/src/features/threads/CustomSnoozeSheet.ios.tsx b/apps/mobile/src/features/threads/CustomSnoozeSheet.ios.tsx index c8d9abbc5fa8..cf123a736559 100644 --- a/apps/mobile/src/features/threads/CustomSnoozeSheet.ios.tsx +++ b/apps/mobile/src/features/threads/CustomSnoozeSheet.ios.tsx @@ -139,7 +139,7 @@ export function CustomSnoozeSheet(props: { modifiers={[ datePickerStyle("wheel"), labelsHidden(), - frame({ maxWidth: Infinity, height: 180 }), + frame({ maxWidth: Infinity, minHeight: 180, maxHeight: 180 }), ]} /> ) : ( @@ -154,7 +154,7 @@ export function CustomSnoozeSheet(props: { modifiers={[ pickerStyle("wheel"), labelsHidden(), - frame({ minWidth: 0, maxWidth: Infinity, height: 180 }), + frame({ minWidth: 0, maxWidth: Infinity, minHeight: 180, maxHeight: 180 }), clipped(), ]} > @@ -177,7 +177,7 @@ export function CustomSnoozeSheet(props: { modifiers={[ pickerStyle("wheel"), labelsHidden(), - frame({ minWidth: 0, maxWidth: Infinity, height: 180 }), + frame({ minWidth: 0, maxWidth: Infinity, minHeight: 180, maxHeight: 180 }), clipped(), ]} > diff --git a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx index 14beefd6d178..d04ad7bc776c 100644 --- a/apps/mobile/src/features/threads/ThreadDetailScreen.tsx +++ b/apps/mobile/src/features/threads/ThreadDetailScreen.tsx @@ -47,6 +47,7 @@ import { useWindowDimensions, View, type GestureResponderEvent, + type ViewInstance, } from "react-native"; import { KeyboardController, @@ -321,7 +322,7 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread const composerEditorRef = useRef(null); const draftMessageRef = useRef(props.draftMessage); draftMessageRef.current = props.draftMessage; - const composerOverlayRef = useRef(null); + const composerOverlayRef = useRef(null); const listRef = useRef(null); const feedTouchStartRef = useRef<{ pageX: number; pageY: number } | null>(null); const selectedThreadKeyRef = useRef(selectedThreadKey); diff --git a/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx b/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx index d9e165bd0107..63f7b48a0bb0 100644 --- a/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx +++ b/apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx @@ -14,9 +14,9 @@ import type { MenuAction } from "@react-native-menu/menu"; import { useAtomValue } from "@effect/atom-react"; import { type EnvironmentId, resolveEnvironmentMachineKind } from "@t3tools/contracts"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import type { LayoutChangeEvent } from "react-native"; +import type { LayoutChangeEvent, TextInputInstance } from "react-native"; import { Platform, StyleSheet, TextInput, View } from "react-native"; -import { Gesture, GestureDetector } from "react-native-gesture-handler"; +import { GestureDetector, useNativeGesture } from "react-native-gesture-handler"; import type { SwipeableMethods } from "react-native-gesture-handler/ReanimatedSwipeable"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import type { SearchBarCommands } from "react-native-screens"; @@ -139,10 +139,10 @@ function ThreadNavigationSidebarPane( const threads = useThreadShells(); const { environments: workspaceEnvironments, state: catalogState } = useWorkspaceState(); const { savedConnectionsById } = useSavedRemoteConnections(); - const searchInputRef = useRef(null); + const searchInputRef = useRef(null); const searchBarRef = useRef(null); const openSwipeableRef = useRef(null); - const sidebarScrollGesture = useMemo(() => Gesture.Native(), []); + const sidebarScrollGesture = useNativeGesture(); const { archiveThread, confirmDeleteThread, diff --git a/apps/mobile/src/features/threads/thread-list-v2-items.tsx b/apps/mobile/src/features/threads/thread-list-v2-items.tsx index 09ffe404ee79..10b01fef0ec7 100644 --- a/apps/mobile/src/features/threads/thread-list-v2-items.tsx +++ b/apps/mobile/src/features/threads/thread-list-v2-items.tsx @@ -523,9 +523,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { readonly activationKey?: string; readonly searchMatch?: EnvironmentThreadSearchMatch; readonly searchQuery?: string; - readonly simultaneousSwipeGesture?: ComponentProps< - typeof ThreadSwipeable - >["simultaneousWithExternalGesture"]; + readonly simultaneousSwipeGesture?: ComponentProps["simultaneousWith"]; }) { const { width: windowWidth } = useWindowDimensions(); const { @@ -1198,7 +1196,7 @@ export const ThreadListV2Row = memo(function ThreadListV2Row(props: { primaryAction={primaryAction} secondaryAction={secondaryAction} resetKey={`${thread.environmentId}:${thread.id}:${variant}:${snoozedRow}:${thread.settledAt}:${thread.unsettledAt}:${thread.snoozedUntil}`} - simultaneousWithExternalGesture={props.simultaneousSwipeGesture} + simultaneousWith={props.simultaneousSwipeGesture} threadTitle={thread.title} > {(close) => ( diff --git a/apps/mobile/src/lib/atomic-file.ts b/apps/mobile/src/lib/atomic-file.ts index 77a695967ff0..97468f44f5dc 100644 --- a/apps/mobile/src/lib/atomic-file.ts +++ b/apps/mobile/src/lib/atomic-file.ts @@ -14,6 +14,6 @@ export async function writeFileAtomically(file: File, contents: string): Promise tempFileSequence += 1; const temp = new FileConstructor(file.parentDirectory, `${file.name}.${tempFileSequence}.tmp`); temp.create({ intermediates: true, overwrite: true }); - temp.write(contents); + await temp.write(contents); temp.moveSync(file, { overwrite: true }); } diff --git a/apps/mobile/src/lib/attachmentUpload.ts b/apps/mobile/src/lib/attachmentUpload.ts index 1bce3e26774f..50b6cf1cee1e 100644 --- a/apps/mobile/src/lib/attachmentUpload.ts +++ b/apps/mobile/src/lib/attachmentUpload.ts @@ -276,7 +276,7 @@ async function uploadFileBytes( try { if (fileUri === undefined && inlineDataUrl !== undefined) { file.create(); - file.write(inlineDataUrl.slice(inlineDataUrl.indexOf(",") + 1), { + await file.write(inlineDataUrl.slice(inlineDataUrl.indexOf(",") + 1), { encoding: "base64", }); } diff --git a/apps/mobile/src/lib/composerImages.ts b/apps/mobile/src/lib/composerImages.ts index 391bf633e557..8fc821d2d26f 100644 --- a/apps/mobile/src/lib/composerImages.ts +++ b/apps/mobile/src/lib/composerImages.ts @@ -161,7 +161,7 @@ export async function persistComposerAttachmentFile( try { let copiedBytes = 0; while (true) { - const chunk = reader.readBytes( + const chunk = await reader.readBytes( Math.min(ATTACHMENT_COPY_CHUNK_BYTES, maxBytes - copiedBytes + 1), ); if (chunk.byteLength === 0) { @@ -171,7 +171,7 @@ export async function persistComposerAttachmentFile( if (copiedBytes > maxBytes) { throw new Error(fileAttachmentTooLargeMessage(name, maxBytes)); } - writer.writeBytes(chunk); + await writer.writeBytes(chunk); } } finally { writer.close(); diff --git a/apps/mobile/src/native/T3ComposerEditor.ios.tsx b/apps/mobile/src/native/T3ComposerEditor.ios.tsx index 5b1a28d5df1c..6eb169a73f87 100644 --- a/apps/mobile/src/native/T3ComposerEditor.ios.tsx +++ b/apps/mobile/src/native/T3ComposerEditor.ios.tsx @@ -13,9 +13,12 @@ import { type Ref, } from "react"; import type { NativeSyntheticEvent, StyleProp, ViewProps, ViewStyle } from "react-native"; -import { Image, StyleSheet } from "react-native"; +import { StyleSheet } from "react-native"; -import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons"; +import { + markdownFileIconSource, + markdownIconAssetUri, +} from "@t3tools/mobile-markdown-text/file-icons"; import { composerChipSizeSuffix, contextChipPresentation, @@ -109,8 +112,8 @@ function basename(path: string): string { return separator >= 0 ? path.slice(separator + 1) : path; } -function fileIconUri(path: string): string { - return Image.resolveAssetSource(markdownFileIconSource(resolveMarkdownFileIcon(path))).uri; +function fileIconUri(path: string): string | null { + return markdownIconAssetUri(markdownFileIconSource(resolveMarkdownFileIcon(path))) ?? null; } export function ComposerEditor({ diff --git a/apps/mobile/src/native/T3ComposerEditor.native.tsx b/apps/mobile/src/native/T3ComposerEditor.native.tsx index 7f18bae0570a..9391a3814c39 100644 --- a/apps/mobile/src/native/T3ComposerEditor.native.tsx +++ b/apps/mobile/src/native/T3ComposerEditor.native.tsx @@ -16,7 +16,10 @@ import { import type { NativeSyntheticEvent, ViewProps } from "react-native"; import { Image, Platform, StyleSheet } from "react-native"; -import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons"; +import { + markdownFileIconSource, + markdownIconAssetUri, +} from "@t3tools/mobile-markdown-text/file-icons"; import { composerChipSizeSuffix, contextChipPresentation, @@ -110,8 +113,8 @@ function basename(path: string): string { return separator >= 0 ? path.slice(separator + 1) : path; } -function fileIconUri(path: string): string { - return Image.resolveAssetSource(markdownFileIconSource(resolveMarkdownFileIcon(path))).uri; +function fileIconUri(path: string): string | null { + return markdownIconAssetUri(markdownFileIconSource(resolveMarkdownFileIcon(path))) ?? null; } export function ComposerEditor({ diff --git a/apps/mobile/src/native/T3ComposerEditor.tsx b/apps/mobile/src/native/T3ComposerEditor.tsx index 22cdf3b53106..5df13972af06 100644 --- a/apps/mobile/src/native/T3ComposerEditor.tsx +++ b/apps/mobile/src/native/T3ComposerEditor.tsx @@ -1,6 +1,6 @@ import { TextInputWrapper } from "expo-paste-input"; import { useImperativeHandle, useRef } from "react"; -import { TextInput, type TextInput as RNTextInput } from "react-native"; +import { TextInput, type TextInputInstance } from "react-native"; import { useFontFamily } from "../lib/useFontFamily"; import { useScaledTextRole } from "../features/settings/appearance/useScaledTextRole"; @@ -21,7 +21,7 @@ export function ComposerEditor({ readOnly = false, ...props }: ComposerEditorProps) { - const inputRef = useRef(null); + const inputRef = useRef(null); const bodyText = useScaledTextRole("body"); const fontFamily = useFontFamily("regular"); const handlePaste = useNativePaste((uris) => onPasteImages?.(uris)); diff --git a/apps/mobile/src/native/T3KeyboardCommands.android.tsx b/apps/mobile/src/native/T3KeyboardCommands.android.tsx index ff4e817c2002..cc01addbad3e 100644 --- a/apps/mobile/src/native/T3KeyboardCommands.android.tsx +++ b/apps/mobile/src/native/T3KeyboardCommands.android.tsx @@ -4,7 +4,7 @@ import type { NativeSyntheticEvent, ViewProps } from "react-native"; import type { HardwareKeyboardCommand } from "../features/keyboard/hardwareKeyboardCommands"; -interface NativeKeyboardCommandsProps extends ViewProps, PropsWithChildren { +interface NativeKeyboardCommandsProps extends ViewProps { readonly enabledCommands: ReadonlyArray; readonly onCommand: ( event: NativeSyntheticEvent<{ readonly command: HardwareKeyboardCommand }>, diff --git a/apps/mobile/src/native/T3KeyboardCommands.ios.tsx b/apps/mobile/src/native/T3KeyboardCommands.ios.tsx index ff4e817c2002..cc01addbad3e 100644 --- a/apps/mobile/src/native/T3KeyboardCommands.ios.tsx +++ b/apps/mobile/src/native/T3KeyboardCommands.ios.tsx @@ -4,7 +4,7 @@ import type { NativeSyntheticEvent, ViewProps } from "react-native"; import type { HardwareKeyboardCommand } from "../features/keyboard/hardwareKeyboardCommands"; -interface NativeKeyboardCommandsProps extends ViewProps, PropsWithChildren { +interface NativeKeyboardCommandsProps extends ViewProps { readonly enabledCommands: ReadonlyArray; readonly onCommand: ( event: NativeSyntheticEvent<{ readonly command: HardwareKeyboardCommand }>, diff --git a/apps/mobile/src/widgets/SubscriptionUsage.tsx b/apps/mobile/src/widgets/SubscriptionUsage.tsx index a32454e5ff83..78197cd2858e 100644 --- a/apps/mobile/src/widgets/SubscriptionUsage.tsx +++ b/apps/mobile/src/widgets/SubscriptionUsage.tsx @@ -29,7 +29,7 @@ function SubscriptionUsage( // The extension evaluates this function without the app's module scope. const family = environment.widgetFamily; // Gallery snapshots can render an old timeline entry after it has expired. - const now = Math.max(environment.date.getTime(), Date.now()); + const now = Math.max(environment.date?.getTime() ?? 0, Date.now()); const accessory = family === "accessoryRectangular"; const compact = family === "systemSmall" || accessory || environment.levelOfDetail === "simplified"; diff --git a/apps/mobile/tsconfig.json b/apps/mobile/tsconfig.json index f6634fbc4c97..146779616fa6 100644 --- a/apps/mobile/tsconfig.json +++ b/apps/mobile/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "expo/tsconfig.base", + "extends": "expo/tsconfig.base.json", "compilerOptions": { "allowImportingTsExtensions": true, "strict": true, diff --git a/apps/web/package.json b/apps/web/package.json index 92b30fba5c92..587faeb2ac02 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -68,7 +68,7 @@ "@types/compression": "^1.8.1", "@types/culori": "^4.0.1", "@types/mdast": "^4.0.4", - "@types/react": "~19.2.14", + "@types/react": "~19.3.0", "@types/react-dom": "~19.2.3", "@types/react-test-renderer": "19.1.0", "@vercel/config": "^0.3.0", diff --git a/patches/@clerk__expo@4.6.8.patch b/patches/@clerk__expo@4.6.8.patch index e9bd5bfe07df..d32b2f29d6ca 100644 --- a/patches/@clerk__expo@4.6.8.patch +++ b/patches/@clerk__expo@4.6.8.patch @@ -1,3 +1,20 @@ +diff --git a/android/build.gradle b/android/build.gradle +index 6bd6d5acf6ac3da78232170a6ea8c2b0f6e5504e..a827dad53dcd8c1b2f47fce30ea8bf9140787f38 100644 +--- a/android/build.gradle ++++ b/android/build.gradle +@@ -146,6 +146,12 @@ dependencies { + implementation "androidx.activity:activity-compose:$activityComposeVersion" + implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion" ++ // ClerkComposeNativeViewHost imports LocalSavedStateRegistryOwner and ++ // LocalLifecycleOwner from these artifacts. Earlier SDKs leaked them onto ++ // the compile classpath through clerk-android-ui's navigation3 runtime ++ // dependency; AGP 9 resolves the compile classpath on its own. ++ implementation "androidx.savedstate:savedstate-compose:1.4.0" ++ implementation "androidx.lifecycle:lifecycle-runtime-compose:2.10.0" + + testImplementation "junit:junit:4.13.2" + } diff --git a/ios/ClerkAuthNativeView.swift b/ios/ClerkAuthNativeView.swift index 5f8d2ba66d5b232890af75c22b173c86d2ef546b..b170304cbf2fbaae8032db8dd6f89b6a59c6e3fe 100644 --- a/ios/ClerkAuthNativeView.swift diff --git a/patches/@expo__metro-config@57.0.12.patch b/patches/@expo__metro-config@58.0.6.patch similarity index 73% rename from patches/@expo__metro-config@57.0.12.patch rename to patches/@expo__metro-config@58.0.6.patch index 26ce34aed6dd..9490a3db95f2 100644 --- a/patches/@expo__metro-config@57.0.12.patch +++ b/patches/@expo__metro-config@58.0.6.patch @@ -1,24 +1,10 @@ diff --git a/build/serializer/sourceMap.js b/build/serializer/sourceMap.js -index 547e53377a7c560db8dfd983601606de15896e07..29a0c855088bceacb7ba00a627615539cbf37738 100644 +index 2a58f57..a90ce77 100644 --- a/build/serializer/sourceMap.js +++ b/build/serializer/sourceMap.js -@@ -27,6 +27,13 @@ function loadSourcemapCodec() { - } - return _sourcemapCodec; - } -+let _traceMapping; -+function loadTraceMapping() { -+ if (!_traceMapping) { -+ _traceMapping = require('@jridgewell/trace-mapping'); -+ } -+ return _traceMapping; -+} - let _Generator; - function loadGenerator() { - if (!_Generator) { -@@ -224,6 +231,58 @@ function repairInvalidNegativeIndices(map) { - } - return changed ? { ...map, mappings: encode(decoded) } : map; +@@ -177,6 +177,58 @@ function repairInvalidNegativeIndices(map) { + mappings: encode(decoded) + } : map; } +// Hermes can emit mappings for Metro trailer/debug lines that have no +// corresponding Metro source-map line. @jridgewell/remapping assumes every @@ -72,11 +58,11 @@ index 547e53377a7c560db8dfd983601606de15896e07..29a0c855088bceacb7ba00a627615539 + } + return sanitized; +} - // `maps[0]` is the original-most transform; `maps[maps.length - 1]` is - // the most recent. Built on `@jridgewell/remapping` instead of mozilla's - // `SourceMapConsumer`-based composer. -@@ -251,7 +310,7 @@ function composeSourceMaps(maps) { - return { ...map, ignoreList: map.x_google_ignoreList }; + function composeSourceMaps(maps) { + if (maps.length < 1) { + throw new Error('composeSourceMaps: Expected at least one map'); +@@ -192,7 +244,7 @@ function composeSourceMaps(maps) { + }; }); // Metro convention is original-first; remapping is most-recent first. - let input = normalized.slice().reverse(); diff --git a/patches/@react-native-menu__menu@2.0.0.patch b/patches/@react-native-menu__menu@2.0.0.patch index 65e6f24a7901..2d79b33b2140 100644 --- a/patches/@react-native-menu__menu@2.0.0.patch +++ b/patches/@react-native-menu__menu@2.0.0.patch @@ -2,6 +2,14 @@ diff --git a/ios/MenuViewManager.mm b/ios/MenuViewManager.mm index 3d149b3e7426b8f7c999603ddf1e15e12331c33a..e80fe2caae86e339fcb03408419a7d64b3e5b04f 100644 --- a/ios/MenuViewManager.mm +++ b/ios/MenuViewManager.mm +@@ -1,6 +1,6 @@ + #import + #import +-#import "RCTBridge.h" ++#import + + #ifdef RCT_NEW_ARCH_ENABLED + // NEW ARCH @@ -65,6 +65,10 @@ - (UIView *)view * onOpenMenu: callback to be called when the menu is opened */ diff --git a/patches/expo-audio@57.0.4.patch b/patches/expo-audio@58.0.3.patch similarity index 80% rename from patches/expo-audio@57.0.4.patch rename to patches/expo-audio@58.0.3.patch index 1452eca31c15..3b4ae1ff4463 100644 --- a/patches/expo-audio@57.0.4.patch +++ b/patches/expo-audio@58.0.3.patch @@ -1,8 +1,8 @@ diff --git a/ios/AudioRecorder.swift b/ios/AudioRecorder.swift -index 20020bff9f8ba7bb6e7f61c99b4de5d29eee00db..284c22f12e30c8c2ed16feb141876cbfd8897c90 100644 +index 73c6a036be6c76e219774a8d1e1cc3a7f18e6f8e..edfbbe00c2b0f3544bcbe42d02b829bf310d241c 100644 --- a/ios/AudioRecorder.swift +++ b/ios/AudioRecorder.swift -@@ -216,15 +216,15 @@ class AudioRecorder: SharedRef, RecordingResultHandler { +@@ -268,16 +268,16 @@ class AudioRecorder: SharedRef, RecordingResultHandler { } func didFinish(_ recorder: AVAudioRecorder, successfully flag: Bool) { @@ -11,6 +11,7 @@ index 20020bff9f8ba7bb6e7f61c99b4de5d29eee00db..284c22f12e30c8c2ed16feb141876cbf + // Update internal state when AVAudioRecorder finishes or fails. + currentState = flag ? .stopped : .error resetDurationTracking() + durationLimitSeconds = nil emit(event: recordingStatus, payload: [ "id": id, diff --git a/patches/expo-blur@58.0.2.patch b/patches/expo-blur@58.0.2.patch new file mode 100644 index 000000000000..f88c657204ff --- /dev/null +++ b/patches/expo-blur@58.0.2.patch @@ -0,0 +1,57 @@ +diff --git a/build/BlurView.types.d.ts b/build/BlurView.types.d.ts +index cc93ffe2cd398a73ac50ebbe5427cbe4187fd83b..7246e9ffbe67af7da4fed20e1e08d0768be812a3 100644 +--- a/build/BlurView.types.d.ts ++++ b/build/BlurView.types.d.ts +@@ -1,5 +1,5 @@ + import type { RefObject } from 'react'; +-import type { ViewProps, View } from 'react-native'; ++import type { ViewProps, ViewInstance } from 'react-native'; + /** + * Blur method to use on Android. + * +@@ -24,7 +24,7 @@ export type BlurViewProps = { + * + * @platform android + */ +- blurTarget?: RefObject; ++ blurTarget?: RefObject; + /** + * A tint mode which will be applied to the view. + * +@@ -68,6 +68,6 @@ export type BlurViewProps = { + blurMethod?: BlurMethod; + } & ViewProps; + export type BlurTargetViewProps = { +- ref?: RefObject; ++ ref?: RefObject; + } & ViewProps; + export type BlurTint = 'light' | 'dark' | 'default' | 'extraLight' | 'regular' | 'prominent' | 'systemUltraThinMaterial' | 'systemThinMaterial' | 'systemMaterial' | 'systemThickMaterial' | 'systemChromeMaterial' | 'systemUltraThinMaterialLight' | 'systemThinMaterialLight' | 'systemMaterialLight' | 'systemThickMaterialLight' | 'systemChromeMaterialLight' | 'systemUltraThinMaterialDark' | 'systemThinMaterialDark' | 'systemMaterialDark' | 'systemThickMaterialDark' | 'systemChromeMaterialDark'; +diff --git a/src/BlurView.types.ts b/src/BlurView.types.ts +index b63ad6b3a9e30bd0f13cff322be79077d0cb5326..bdc3295af94bc17e8a6457b6c9567ff2d57799a7 100644 +--- a/src/BlurView.types.ts ++++ b/src/BlurView.types.ts +@@ -1,5 +1,5 @@ + import type { RefObject } from 'react'; +-import type { ViewProps, View } from 'react-native'; ++import type { ViewProps, ViewInstance } from 'react-native'; + + /** + * Blur method to use on Android. +@@ -27,7 +27,7 @@ export type BlurViewProps = { + * + * @platform android + */ +- blurTarget?: RefObject; ++ blurTarget?: RefObject; + /** + * A tint mode which will be applied to the view. + * +@@ -74,7 +74,7 @@ export type BlurViewProps = { + } & ViewProps; + + export type BlurTargetViewProps = { +- ref?: RefObject; ++ ref?: RefObject; + } & ViewProps; + + export type BlurTint = diff --git a/patches/expo-glass-effect@58.0.3.patch b/patches/expo-glass-effect@58.0.3.patch new file mode 100644 index 000000000000..23d09d012608 --- /dev/null +++ b/patches/expo-glass-effect@58.0.3.patch @@ -0,0 +1,72 @@ +diff --git a/build/GlassContainer.types.d.ts b/build/GlassContainer.types.d.ts +index 502f9b037900d62aa5875dc37f0fcb517dec7a44..cc521dcb7e411cba7dfe99f191bbc42ac979849f 100644 +--- a/build/GlassContainer.types.d.ts ++++ b/build/GlassContainer.types.d.ts +@@ -1,5 +1,5 @@ + import type { Ref } from 'react'; +-import type { View, ViewProps } from 'react-native'; ++import type { ViewInstance, ViewProps } from 'react-native'; + export type GlassContainerProps = { + /** + * The distance at which glass elements start affecting each other. +@@ -7,5 +7,5 @@ export type GlassContainerProps = { + * @default undefined + */ + spacing?: number; +- ref?: Ref; ++ ref?: Ref; + } & ViewProps; +diff --git a/build/GlassView.types.d.ts b/build/GlassView.types.d.ts +index a09487b1b3ef2e4d89b19e2bad81f99fc532d94d..eeadfff1dcd891bf581ef6be0493e2a6eda0849a 100644 +--- a/build/GlassView.types.d.ts ++++ b/build/GlassView.types.d.ts +@@ -1,5 +1,5 @@ + import type { Ref } from 'react'; +-import type { ColorValue, View, ViewProps } from 'react-native'; ++import type { ColorValue, ViewInstance, ViewProps } from 'react-native'; + export type GlassStyle = 'clear' | 'regular' | 'none'; + export type GlassEffectStyleConfig = { + /** +@@ -40,5 +40,5 @@ export type GlassViewProps = { + * @default 'auto' + */ + colorScheme?: GlassColorScheme; +- ref?: Ref; ++ ref?: Ref; + } & ViewProps; +diff --git a/src/GlassContainer.types.ts b/src/GlassContainer.types.ts +index f57a30713a4a2c1769e4f213a43d29fa17d8c411..fa934d45d488dcbc8cb6396e88f0a2996834367b 100644 +--- a/src/GlassContainer.types.ts ++++ b/src/GlassContainer.types.ts +@@ -1,5 +1,5 @@ + import type { Ref } from 'react'; +-import type { View, ViewProps } from 'react-native'; ++import type { ViewInstance, ViewProps } from 'react-native'; + + export type GlassContainerProps = { + /** +@@ -8,5 +8,5 @@ export type GlassContainerProps = { + * @default undefined + */ + spacing?: number; +- ref?: Ref; ++ ref?: Ref; + } & ViewProps; +diff --git a/src/GlassView.types.ts b/src/GlassView.types.ts +index 7fc30003a9337a12ffb12ffb44a050aae99e9b40..413db6b698055dd00d6ec2cf7b71e4370c85054c 100644 +--- a/src/GlassView.types.ts ++++ b/src/GlassView.types.ts +@@ -1,5 +1,5 @@ + import type { Ref } from 'react'; +-import type { ColorValue, View, ViewProps } from 'react-native'; ++import type { ColorValue, ViewInstance, ViewProps } from 'react-native'; + + export type GlassStyle = 'clear' | 'regular' | 'none'; + +@@ -44,5 +44,5 @@ export type GlassViewProps = { + * @default 'auto' + */ + colorScheme?: GlassColorScheme; +- ref?: Ref; ++ ref?: Ref; + } & ViewProps; diff --git a/patches/expo-sharing@57.0.17.patch b/patches/expo-sharing@58.0.12.patch similarity index 91% rename from patches/expo-sharing@57.0.17.patch rename to patches/expo-sharing@58.0.12.patch index 924df6c8c7c1..dd3bec580b17 100644 --- a/patches/expo-sharing@57.0.17.patch +++ b/patches/expo-sharing@58.0.12.patch @@ -1,5 +1,5 @@ diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt -index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644 +index 0b87b53..65f1c57 100644 --- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt +++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt @@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable { @@ -13,7 +13,7 @@ index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b83 @OptimizedRecord diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt -index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644 +index 8dd50e8..481cdb4 100644 --- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt +++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt @@ -3,6 +3,7 @@ package expo.modules.sharing @@ -89,10 +89,10 @@ index 8dd50e8f04022d183884a57e4d61a7e1711b9e49..481cdb4bc64ea5ae49919071f686324f } } diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts -index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01c8728fcc 100644 +index 74544e0..92bd2f5 100644 --- a/build/Sharing.types.d.ts +++ b/build/Sharing.types.d.ts -@@ -77,6 +77,11 @@ export type SharePayload = { +@@ -100,6 +100,11 @@ export type SharePayload = { * @default 'text/plain' */ mimeType?: string; @@ -105,10 +105,10 @@ index e9820b061bddce91657ab7144fde98d0543a3b8e..364d63273cb3e209c6490de6dd869a01 export type BaseResolvedSharePayload = SharePayload & { /** diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts -index d9a5ad38f5fe2856b365eb91b71abd640314a5cc..21ea45f04b88cce272e2e02de24c5e4eb8157e82 100644 +index 18af320..3a52b70 100644 --- a/src/Sharing.types.ts +++ b/src/Sharing.types.ts -@@ -85,6 +85,12 @@ export type SharePayload = { +@@ -108,6 +108,12 @@ export type SharePayload = { * @default 'text/plain' */ mimeType?: string; diff --git a/patches/expo-widgets@57.0.15.patch b/patches/expo-widgets@58.0.9.patch similarity index 80% rename from patches/expo-widgets@57.0.15.patch rename to patches/expo-widgets@58.0.9.patch index f50a3fa4f661..f2632f180c84 100644 --- a/patches/expo-widgets@57.0.15.patch +++ b/patches/expo-widgets@58.0.9.patch @@ -1,8 +1,8 @@ diff --git a/build/Widgets.types.d.ts b/build/Widgets.types.d.ts -index 15e026868625ce20a3e359e5cc8e5c7e937c4650..f5cc83174ede4fb6e01cbce494f61e088eb4eed8 100644 +index c9f4dfe..dc0792e 100644 --- a/build/Widgets.types.d.ts +++ b/build/Widgets.types.d.ts -@@ -90,6 +90,10 @@ export type LiveActivityEnvironment = { +@@ -93,6 +93,10 @@ export type LiveActivityEnvironment = { * The color scheme of the activity's environment. */ colorScheme: 'light' | 'dark'; @@ -14,27 +14,27 @@ index 15e026868625ce20a3e359e5cc8e5c7e937c4650..f5cc83174ede4fb6e01cbce494f61e08 * Whether the activity is displayed in a context with reduced luminance. * @platform iOS 16+ diff --git a/ios/Widgets/Utils.swift b/ios/Widgets/Utils.swift -index 2b4c044b597de7e0fab42dbc47af14d8bb521838..801f0aed65ea2659f221d477dd841787d9146c26 100644 +index 76b2199..6cb52c3 100644 --- a/ios/Widgets/Utils.swift +++ b/ios/Widgets/Utils.swift -@@ -91,6 +91,10 @@ func getLiveActivityEnvironment(for environment: EnvironmentValues, in context: - "colorScheme": "\(environment.colorScheme)" +@@ -125,6 +125,10 @@ func getLiveActivityEnvironment(for environment: EnvironmentValues, in context: + "isStale": context.isStale ] + if #available(iOS 26.0, *) { + env["isLiquidGlassAvailable"] = true + } + env["widgetRenderingMode"] = environment.widgetRenderingMode.description - env["isLuminanceReduced"] = environment.isLuminanceReduced - env["isActivityFullscreen"] = environment.isActivityFullscreen - if #available(iOS 16.2, *) { + if #available(iOS 18.0, *) { + env["isActivityUpdateReduced"] = environment.isActivityUpdateReduced + env["activityFamily"] = "\(environment.activityFamily)" diff --git a/ios/Widgets/WidgetLiveActivity.swift b/ios/Widgets/WidgetLiveActivity.swift -index 24d4571a52d3ebe9d785b5d049d8e134a149d513..7051c23b17ac91552e5b5c54606c57086c0ebbea 100644 +index 4d135c4..dae4744 100644 --- a/ios/Widgets/WidgetLiveActivity.swift +++ b/ios/Widgets/WidgetLiveActivity.swift -@@ -20,53 +20,41 @@ struct LiveActivityAttributes: ActivityAttributes { +@@ -19,53 +19,41 @@ struct LiveActivityAttributes: ActivityAttributes { + } - @available(iOS 16.1, *) public struct WidgetLiveActivity: Widget { - @Environment(\.self) var env - @@ -94,9 +94,9 @@ index 24d4571a52d3ebe9d785b5d049d8e134a149d513..7051c23b17ac91552e5b5c54606c5708 } if let url = context.attributes.url.flatMap(URL.init(string:)) { return island.widgetURL(url) -@@ -79,11 +67,16 @@ public struct WidgetLiveActivity: Widget { +@@ -77,11 +65,16 @@ public struct WidgetLiveActivity: Widget { + } - @available(iOS 16.1, *) private struct LiveActivitySectionView: View { + @Environment(\.self) var env let context: ActivityViewContext @@ -112,9 +112,9 @@ index 24d4571a52d3ebe9d785b5d049d8e134a149d513..7051c23b17ac91552e5b5c54606c5708 if let node = nodes[sectionName] as? [String: Any] { WidgetsDynamicView(name: context.activityID, kind: .liveActivity, node: node) } else { -@@ -94,10 +87,17 @@ private struct LiveActivitySectionView: View { +@@ -91,10 +84,17 @@ private struct LiveActivitySectionView: View { + } - @available(iOS 16.1, *) private struct LiveActivityBannerView: View { + // Read inside the rendered view: Widget-level values do not include the + // presentation's color scheme, rendering mode, or reduced-luminance state. @@ -131,11 +131,25 @@ index 24d4571a52d3ebe9d785b5d049d8e134a149d513..7051c23b17ac91552e5b5c54606c5708 if #available(iOS 18.0, *) { LiveActivityBanner(context: context, nodes: nodes) } else if let node = nodes["banner"] as? [String: Any] { +diff --git a/scripts/build-layout-registry.mjs b/scripts/build-layout-registry.mjs +index d52a60e..fa9bd77 100644 +--- a/scripts/build-layout-registry.mjs ++++ b/scripts/build-layout-registry.mjs +@@ -154,6 +154,8 @@ function createLayoutRegistry(expectedWidgets, capturedLayouts) { + return registry; + } + +-if (process.argv[1] && path.resolve(process.argv[1]) === __filename) { ++// Compare real paths: pnpm exposes the package through a symlink, so the ++// invoked path and import.meta.url differ while naming the same file. ++if (process.argv[1] && fs.realpathSync(path.resolve(process.argv[1])) === fs.realpathSync(__filename)) { + await main(); + } diff --git a/src/Widgets.types.ts b/src/Widgets.types.ts -index fee5c7475b52218fa0e192a1d347dd32cb0fe1f8..1d3a097b45d8eb5d13e5cedd26f0414caa83a5d6 100644 +index 0770613..924fa00 100644 --- a/src/Widgets.types.ts +++ b/src/Widgets.types.ts -@@ -104,6 +104,10 @@ export type LiveActivityEnvironment = { +@@ -107,6 +107,10 @@ export type LiveActivityEnvironment = { * The color scheme of the activity's environment. */ colorScheme: 'light' | 'dark'; diff --git a/patches/react-native-gesture-handler@2.32.0.patch b/patches/react-native-gesture-handler@2.32.0.patch deleted file mode 100644 index ae3568fa64a9..000000000000 --- a/patches/react-native-gesture-handler@2.32.0.patch +++ /dev/null @@ -1,237 +0,0 @@ -diff --git a/apple/Handlers/RNHoverHandler.m b/apple/Handlers/RNHoverHandler.m -index 320cb8cb2652bfcfe1ecc65ebd81a8d208e4260f..a88ac5f04a9663fd7a62ee89e42d85ec41dcaf55 100644 ---- a/apple/Handlers/RNHoverHandler.m -+++ b/apple/Handlers/RNHoverHandler.m -@@ -132,8 +132,10 @@ - (void)unbindFromView - { - #if CHECK_TARGET(13_4) - if (@available(iOS 13.4, *)) { -+ // The superclass detaches the recognizer, clearing recognizer.view. Remove -+ // the interaction from its own view before it can be recycled by Fabric. -+ [_pointerInteraction.view removeInteraction:_pointerInteraction]; - [super unbindFromView]; -- [self.recognizer.view removeInteraction:_pointerInteraction]; - } - #endif - } -diff --git a/lib/commonjs/components/ReanimatedSwipeable/ReanimatedSwipeable.js b/lib/commonjs/components/ReanimatedSwipeable/ReanimatedSwipeable.js -index 551ab92bf58db0b79d428dcd2f2df898ef686493..13db26d88bff975bc5d46bb6432cbf9fda3d489a 100644 ---- a/lib/commonjs/components/ReanimatedSwipeable/ReanimatedSwipeable.js -+++ b/lib/commonjs/components/ReanimatedSwipeable/ReanimatedSwipeable.js -@@ -34,11 +34,13 @@ const Swipeable = props => { - enableTrackpadTwoFingerGesture = DEFAULT_ENABLE_TRACKING_TWO_FINGER_GESTURE, - dragOffsetFromLeftEdge = DEFAULT_DRAG_OFFSET, - dragOffsetFromRightEdge = DEFAULT_DRAG_OFFSET, -+ failOffsetY, - friction = DEFAULT_FRICTION, - overshootFriction = DEFAULT_OVERSHOOT_FRICTION, - onSwipeableOpenStartDrag, - onSwipeableCloseStartDrag, - onSwipeableWillOpen, -+ onSwipeableRelease, - onSwipeableWillClose, - onSwipeableOpen, - onSwipeableClose, -@@ -248,8 +250,13 @@ const Swipeable = props => { - toValue = -rightWidth.value; - } - } -+ // Let a UI-thread full-swipe commit take over before the return spring. -+ if (onSwipeableRelease?.(appliedTranslation)) { -+ return; -+ } -+ - animateRow(toValue, velocityX / friction); -- }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag]); -+ }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag, onSwipeableRelease, appliedTranslation]); - const close = (0, _react.useCallback)(() => { - 'worklet'; - -@@ -285,11 +292,14 @@ const Swipeable = props => { - }).onFinalize(() => { - dragStarted.value = false; - }); -+ if (failOffsetY !== undefined) { -+ pan.failOffsetY(failOffsetY); -+ } - Object.entries(relationProps).forEach(([relationName, relation]) => { - (0, _utils.applyRelationProp)(pan, relationName, relation); - }); - return pan; -- }, [enabled, hitSlop, enableTrackpadTwoFingerGesture, dragOffsetFromRightEdge, dragOffsetFromLeftEdge, updateElementWidths, relationProps, userDrag, rowState, dragStarted, updateAnimatedEvent, onSwipeableOpenStartDrag, onSwipeableCloseStartDrag, handleRelease]); -+ }, [enabled, hitSlop, enableTrackpadTwoFingerGesture, dragOffsetFromRightEdge, dragOffsetFromLeftEdge, failOffsetY, updateElementWidths, relationProps, userDrag, rowState, dragStarted, updateAnimatedEvent, onSwipeableOpenStartDrag, onSwipeableCloseStartDrag, handleRelease]); - (0, _react.useImperativeHandle)(ref, () => swipeableMethods, [swipeableMethods]); - const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({ - transform: [{ -diff --git a/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js b/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js -index a2835d5416ffd5cf9a04e98774516b9e6569691e..055afce410d6eb655532e7a09371dfc22eae5e9c 100644 ---- a/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js -+++ b/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js -@@ -29,11 +29,13 @@ const Swipeable = props => { - enableTrackpadTwoFingerGesture = DEFAULT_ENABLE_TRACKING_TWO_FINGER_GESTURE, - dragOffsetFromLeftEdge = DEFAULT_DRAG_OFFSET, - dragOffsetFromRightEdge = DEFAULT_DRAG_OFFSET, -+ failOffsetY, - friction = DEFAULT_FRICTION, - overshootFriction = DEFAULT_OVERSHOOT_FRICTION, - onSwipeableOpenStartDrag, - onSwipeableCloseStartDrag, - onSwipeableWillOpen, -+ onSwipeableRelease, - onSwipeableWillClose, - onSwipeableOpen, - onSwipeableClose, -@@ -243,8 +245,13 @@ const Swipeable = props => { - toValue = -rightWidth.value; - } - } -+ // Let a UI-thread full-swipe commit take over before the return spring. -+ if (onSwipeableRelease?.(appliedTranslation)) { -+ return; -+ } -+ - animateRow(toValue, velocityX / friction); -- }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag]); -+ }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag, onSwipeableRelease, appliedTranslation]); - const close = useCallback(() => { - 'worklet'; - -@@ -280,11 +287,14 @@ const Swipeable = props => { - }).onFinalize(() => { - dragStarted.value = false; - }); -+ if (failOffsetY !== undefined) { -+ pan.failOffsetY(failOffsetY); -+ } - Object.entries(relationProps).forEach(([relationName, relation]) => { - applyRelationProp(pan, relationName, relation); - }); - return pan; -- }, [enabled, hitSlop, enableTrackpadTwoFingerGesture, dragOffsetFromRightEdge, dragOffsetFromLeftEdge, updateElementWidths, relationProps, userDrag, rowState, dragStarted, updateAnimatedEvent, onSwipeableOpenStartDrag, onSwipeableCloseStartDrag, handleRelease]); -+ }, [enabled, hitSlop, enableTrackpadTwoFingerGesture, dragOffsetFromRightEdge, dragOffsetFromLeftEdge, failOffsetY, updateElementWidths, relationProps, userDrag, rowState, dragStarted, updateAnimatedEvent, onSwipeableOpenStartDrag, onSwipeableCloseStartDrag, handleRelease]); - useImperativeHandle(ref, () => swipeableMethods, [swipeableMethods]); - const animatedStyle = useAnimatedStyle(() => ({ - transform: [{ -diff --git a/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts b/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts -index ac8b76830d468edfbc29052b452a36221323c3de..cac72ebaafaf746af7640783a16e99c93ecad2a4 100644 ---- a/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts -+++ b/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts -@@ -64,6 +64,13 @@ export interface SwipeableProps { - * a swipe. The default value is 10. - */ - dragOffsetFromRightEdge?: number; -+ /** -+ * Range along the Y axis (in points) that, once exceeded before the swipe -+ * activates, makes the pan fail. Lets vertically-dominant pans (list -+ * scrolling, especially trackpad two-finger pans) skip the swipe entirely. -+ * Passed straight to the underlying Pan gesture's `failOffsetY`. -+ */ -+ failOffsetY?: number | [start: number, end: number]; - /** - * Value indicating if the swipeable panel can be pulled further than the left - * actions panel's width. It is set to true by default as long as the left -@@ -90,6 +97,13 @@ export interface SwipeableProps { - * Called when action panel is closed. - */ - onSwipeableClose?: (direction: SwipeDirection.LEFT | SwipeDirection.RIGHT) => void; -+ /** -+ * UI-thread worklet called on release before the built-in spring starts. -+ * Return true to consume the release and take ownership of translation. -+ * The caller must reset or remove the row after its custom animation. -+ */ -+ onSwipeableRelease?: (translation: SharedValue) => boolean; -+ - /** - * Called when action panel starts animating on open (either right or left). - */ -diff --git a/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx -index b6134c908624adc590ebd264e90e558b88e235d5..fa4b1c1749bd0e86cbf5f5546f295d8099e1a481 100644 ---- a/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx -+++ b/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx -@@ -58,11 +58,13 @@ const Swipeable = (props: SwipeableProps) => { - enableTrackpadTwoFingerGesture = DEFAULT_ENABLE_TRACKING_TWO_FINGER_GESTURE, - dragOffsetFromLeftEdge = DEFAULT_DRAG_OFFSET, - dragOffsetFromRightEdge = DEFAULT_DRAG_OFFSET, -+ failOffsetY, - friction = DEFAULT_FRICTION, - overshootFriction = DEFAULT_OVERSHOOT_FRICTION, - onSwipeableOpenStartDrag, - onSwipeableCloseStartDrag, - onSwipeableWillOpen, -+ onSwipeableRelease, - onSwipeableWillClose, - onSwipeableOpen, - onSwipeableClose, -@@ -457,6 +459,11 @@ const Swipeable = (props: SwipeableProps) => { - } - } - -+ // Let a UI-thread full-swipe commit take over before the return spring. -+ if (onSwipeableRelease?.(appliedTranslation)) { -+ return; -+ } -+ - animateRow(toValue, velocityX / friction); - }, - [ -@@ -468,6 +475,8 @@ const Swipeable = (props: SwipeableProps) => { - rightWidth, - rowState, - userDrag, -+ onSwipeableRelease, -+ appliedTranslation, - ] - ); - -@@ -537,6 +546,10 @@ const Swipeable = (props: SwipeableProps) => { - dragStarted.value = false; - }); - -+ if (failOffsetY !== undefined) { -+ pan.failOffsetY(failOffsetY); -+ } -+ - Object.entries(relationProps).forEach(([relationName, relation]) => { - applyRelationProp( - pan, -@@ -552,6 +565,7 @@ const Swipeable = (props: SwipeableProps) => { - enableTrackpadTwoFingerGesture, - dragOffsetFromRightEdge, - dragOffsetFromLeftEdge, -+ failOffsetY, - updateElementWidths, - relationProps, - userDrag, -diff --git a/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts b/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts -index 0c0e517e0d340faf50ff78c3d48e7a2bbcf808ec..3ab14d240da346b1927792e480f5b1e902b03bf8 100644 ---- a/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts -+++ b/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts -@@ -77,6 +77,14 @@ export interface SwipeableProps { - */ - dragOffsetFromRightEdge?: number; - -+ /** -+ * Range along the Y axis (in points) that, once exceeded before the swipe -+ * activates, makes the pan fail. Lets vertically-dominant pans (list -+ * scrolling, especially trackpad two-finger pans) skip the swipe entirely. -+ * Passed straight to the underlying Pan gesture's `failOffsetY`. -+ */ -+ failOffsetY?: number | [start: number, end: number]; -+ - /** - * Value indicating if the swipeable panel can be pulled further than the left - * actions panel's width. It is set to true by default as long as the left -@@ -112,6 +120,13 @@ export interface SwipeableProps { - direction: SwipeDirection.LEFT | SwipeDirection.RIGHT - ) => void; - -+ /** -+ * UI-thread worklet called on release before the built-in spring starts. -+ * Return true to consume the release and take ownership of translation. -+ * The caller must reset or remove the row after its custom animation. -+ */ -+ onSwipeableRelease?: (translation: SharedValue) => boolean; -+ - /** - * Called when action panel starts animating on open (either right or left). - */ diff --git a/patches/react-native-gesture-handler@3.2.1.patch b/patches/react-native-gesture-handler@3.2.1.patch new file mode 100644 index 000000000000..8fe606a1fad6 --- /dev/null +++ b/patches/react-native-gesture-handler@3.2.1.patch @@ -0,0 +1,151 @@ +diff --git a/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js b/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js +index 4ab38424d1f5fc8b2686dd4a0a8058c454a9874d..0c5e0eaa995af50e5f8c02909dc6825121cc61af 100644 +--- a/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js ++++ b/lib/module/components/ReanimatedSwipeable/ReanimatedSwipeable.js +@@ -31,11 +31,13 @@ const Swipeable = props => { + enableTrackpadTwoFingerGesture = DEFAULT_ENABLE_TRACKING_TWO_FINGER_GESTURE, + dragOffsetFromLeft = DEFAULT_DRAG_OFFSET, + dragOffsetFromRight = -DEFAULT_DRAG_OFFSET, ++ failOffsetY, + friction = DEFAULT_FRICTION, + overshootFriction = DEFAULT_OVERSHOOT_FRICTION, + onSwipeableOpenStartDrag, + onSwipeableCloseStartDrag, + onSwipeableWillOpen, ++ onSwipeableRelease, + onSwipeableWillClose, + onSwipeableOpen, + onSwipeableClose, +@@ -276,8 +278,12 @@ const Swipeable = props => { + toValue = -rightWidth.value; + } + } ++ // Let a UI-thread full-swipe commit take over before the return spring. ++ if (onSwipeableRelease?.(appliedTranslation)) { ++ return; ++ } + animateRow(toValue, velocityX / friction); +- }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag]); ++ }, [animateRow, friction, leftThreshold, leftWidth, rightThreshold, rightWidth, rowState, userDrag, onSwipeableRelease, appliedTranslation]); + const close = useCallback(() => { + 'worklet'; + +@@ -302,6 +308,7 @@ const Swipeable = props => { + enabled: enabled ?? true, + enableTrackpadTwoFingerGesture: enableTrackpadTwoFingerGesture, + activeOffsetX: [dragOffsetFromRight, dragOffsetFromLeft], ++ failOffsetY, + simultaneousWith, + requireToFail, + block, +diff --git a/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts b/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts +index e97b6dbbced1bcbd359cf35293b7f10cbf13b0e7..de07f26423bee66ecd7d0f9bb33233bcb3215751 100644 +--- a/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts ++++ b/lib/typescript/components/ReanimatedSwipeable/ReanimatedSwipeableProps.d.ts +@@ -59,6 +59,12 @@ export type SwipeableProps = { + * Called when action panel is closed. + */ + onSwipeableClose?: (direction: SwipeDirection.LEFT | SwipeDirection.RIGHT) => void; ++ /** ++ * UI-thread worklet called on release before the built-in spring starts. ++ * Return true to consume the release and take ownership of translation. ++ * The caller must reset or remove the row after its custom animation. ++ */ ++ onSwipeableRelease?: (translation: SharedValue) => boolean; + /** + * Called when action panel starts animating on open (either right or left). + */ +@@ -150,6 +156,13 @@ export type SwipeableProps = { + * The horizontal offset from the starting point required to trigger a left-swipe gesture. Defaults to -10. + */ + dragOffsetFromRight?: number; ++ /** ++ * Range along the Y axis (in points) that, once exceeded before the swipe ++ * activates, makes the pan fail. Lets vertically-dominant pans (list ++ * scrolling, especially trackpad two-finger pans) skip the swipe entirely. ++ * Passed straight to the underlying Pan gesture's `failOffsetY`. ++ */ ++ failOffsetY?: number | [start: number, end: number]; + }>; + export interface SwipeableMethods { + close: () => void; +diff --git a/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx b/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx +index 4881db1dc7575adc6610569035a8990cee414f3e..8431b738a9ffd09df48e1106b2bd5b62251d536c 100644 +--- a/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx ++++ b/src/components/ReanimatedSwipeable/ReanimatedSwipeable.tsx +@@ -61,11 +61,13 @@ const Swipeable = (props: SwipeableProps) => { + enableTrackpadTwoFingerGesture = DEFAULT_ENABLE_TRACKING_TWO_FINGER_GESTURE, + dragOffsetFromLeft = DEFAULT_DRAG_OFFSET, + dragOffsetFromRight = -DEFAULT_DRAG_OFFSET, ++ failOffsetY, + friction = DEFAULT_FRICTION, + overshootFriction = DEFAULT_OVERSHOOT_FRICTION, + onSwipeableOpenStartDrag, + onSwipeableCloseStartDrag, + onSwipeableWillOpen, ++ onSwipeableRelease, + onSwipeableWillClose, + onSwipeableOpen, + onSwipeableClose, +@@ -491,6 +493,11 @@ const Swipeable = (props: SwipeableProps) => { + } + } + ++ // Let a UI-thread full-swipe commit take over before the return spring. ++ if (onSwipeableRelease?.(appliedTranslation)) { ++ return; ++ } ++ + animateRow(toValue, velocityX / friction); + }, + [ +@@ -502,6 +509,8 @@ const Swipeable = (props: SwipeableProps) => { + rightWidth, + rowState, + userDrag, ++ onSwipeableRelease, ++ appliedTranslation, + ] + ); + +@@ -530,6 +539,7 @@ const Swipeable = (props: SwipeableProps) => { + enabled: enabled ?? true, + enableTrackpadTwoFingerGesture: enableTrackpadTwoFingerGesture, + activeOffsetX: [dragOffsetFromRight, dragOffsetFromLeft], ++ failOffsetY, + simultaneousWith, + requireToFail, + block, +diff --git a/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts b/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts +index 1e1246f709feb04c01cf3221472cc1219a8fffac..f526d4fe2d2738becbe8d29c59d1105afa11ae60 100644 +--- a/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts ++++ b/src/components/ReanimatedSwipeable/ReanimatedSwipeableProps.ts +@@ -77,6 +77,13 @@ export type SwipeableProps = { + direction: SwipeDirection.LEFT | SwipeDirection.RIGHT + ) => void; + ++ /** ++ * UI-thread worklet called on release before the built-in spring starts. ++ * Return true to consume the release and take ownership of translation. ++ * The caller must reset or remove the row after its custom animation. ++ */ ++ onSwipeableRelease?: (translation: SharedValue) => boolean; ++ + /** + * Called when action panel starts animating on open (either right or left). + */ +@@ -196,6 +203,14 @@ export type SwipeableProps = { + * The horizontal offset from the starting point required to trigger a left-swipe gesture. Defaults to -10. + */ + dragOffsetFromRight?: number; ++ ++ /** ++ * Range along the Y axis (in points) that, once exceeded before the swipe ++ * activates, makes the pan fail. Lets vertically-dominant pans (list ++ * scrolling, especially trackpad two-finger pans) skip the swipe entirely. ++ * Passed straight to the underlying Pan gesture's `failOffsetY`. ++ */ ++ failOffsetY?: number | [start: number, end: number]; + }>; + + export interface SwipeableMethods { diff --git a/patches/react-native-keyboard-controller@1.21.13.patch b/patches/react-native-keyboard-controller@1.22.4.patch similarity index 89% rename from patches/react-native-keyboard-controller@1.21.13.patch rename to patches/react-native-keyboard-controller@1.22.4.patch index f2e510a940bf..58c26f740a6c 100644 --- a/patches/react-native-keyboard-controller@1.21.13.patch +++ b/patches/react-native-keyboard-controller@1.22.4.patch @@ -1,8 +1,8 @@ diff --git a/lib/commonjs/components/KeyboardChatScrollView/index.js b/lib/commonjs/components/KeyboardChatScrollView/index.js -index db8cfb1d289f91563f13c4dd842c783c99facc32..64c7e38ad8d9e866b15a53e561509e6b0ad33cb9 100644 +index 5617394..4f2222a 100644 --- a/lib/commonjs/components/KeyboardChatScrollView/index.js +++ b/lib/commonjs/components/KeyboardChatScrollView/index.js -@@ -26,9 +26,12 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ +@@ -27,9 +27,12 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ offset = 0, extraContentPadding = ZERO_CONTENT_PADDING, blankSpace = ZERO_BLANK_SPACE, @@ -15,7 +15,7 @@ index db8cfb1d289f91563f13c4dd842c783c99facc32..64c7e38ad8d9e866b15a53e561509e6b onEndVisible, ...rest }, ref) => { -@@ -50,13 +53,17 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ +@@ -51,13 +54,17 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ freeze: freezeSV, offset, blankSpace, @@ -34,7 +34,7 @@ index db8cfb1d289f91563f13c4dd842c783c99facc32..64c7e38ad8d9e866b15a53e561509e6b scroll, layout, size, -@@ -82,10 +89,26 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ +@@ -88,10 +95,26 @@ const KeyboardChatScrollView = /*#__PURE__*/(0, _react.forwardRef)(({ // a bug for you, please open an issue. const totalPadding = (0, _reactNativeReanimated.useDerivedValue)(() => Math.min(layout.value.height, Math.max(blankSpace.value, padding.value + extraContentPadding.value))); @@ -63,7 +63,7 @@ index db8cfb1d289f91563f13c4dd842c783c99facc32..64c7e38ad8d9e866b15a53e561509e6b onLayoutInternal(e); onLayoutProp === null || onLayoutProp === void 0 || onLayoutProp(e); diff --git a/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js b/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js -index 4d33b3fe426070cf312fc493ce902b2c24d853ea..e619708b95865afd8b43dd8f0a6523fcf67b1f53 100644 +index 4d33b3f..6a787d3 100644 --- a/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +++ b/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/helpers.js @@ -206,7 +206,7 @@ const clampedScrollTarget = (offsetBeforeScroll, keyboardHeight, contentHeight, @@ -87,8 +87,9 @@ index 4d33b3fe426070cf312fc493ce902b2c24d853ea..e619708b95865afd8b43dd8f0a6523fc }; exports.computeIOSContentOffset = computeIOSContentOffset; //# sourceMappingURL=helpers.js.map +\ No newline at end of file diff --git a/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js b/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js -index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d9547a27c 100644 +index cecee07..533a9e9 100644 --- a/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +++ b/lib/commonjs/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js @@ -32,7 +32,9 @@ function useChatKeyboard(scrollViewRef, options) { @@ -102,7 +103,7 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d } = options; const padding = (0, _reactNativeReanimated.useSharedValue)(0); const currentHeight = (0, _reactNativeReanimated.useSharedValue)(0); -@@ -58,6 +60,9 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -59,6 +61,9 @@ function useChatKeyboard(scrollViewRef, options) { targetKeyboardHeight.value = e.height; } const effective = (0, _helpers.getEffectiveHeight)(e.height, targetKeyboardHeight.value, offset); @@ -112,16 +113,16 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d const atEnd = (0, _helpers.isScrollAtEnd)(scroll.value, layout.value.height, size.value.height, inverted); // Scale minimum padding absorption by how much of it is visible. -@@ -66,7 +71,7 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -67,7 +72,7 @@ function useChatKeyboard(scrollViewRef, options) { const visiblePadding = visibleFraction * blankSpace.value; const minimumPaddingAbsorbed = Math.max(0, visiblePadding - extraContentPadding.value); const scrollEffective = (0, _helpers.getScrollEffective)(effective, minimumPaddingAbsorbed); - const actualTotalPadding = Math.max(blankSpace.value, effective + extraContentPadding.value); + const actualTotalPadding = Math.max(blankSpace.value, effective + extraContentPadding.value) + adjustedInsetCompensation; - // persistent mode: when keyboard shrinks, clamp to valid range - if (keyboardLiftBehavior === "persistent" && effective < padding.value) { -@@ -76,8 +81,8 @@ function useChatKeyboard(scrollViewRef, options) { + // `onInteractive` owns the native scroll offset. When its final + // keyboardWillHide event arrives, consume the marker so this +@@ -87,8 +92,8 @@ function useChatKeyboard(scrollViewRef, options) { const maxScroll = Math.max(size.value.height - layout.value.height, 0); contentOffsetY.value = Math.max(-actualTotalPadding, Math.min(scroll.value, maxScroll)); } else { @@ -132,7 +133,7 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d } return; } -@@ -91,8 +96,8 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -102,8 +107,8 @@ function useChatKeyboard(scrollViewRef, options) { const maxScroll = Math.max(size.value.height - layout.value.height, 0); contentOffsetY.value = Math.max(-actualTotalPadding, Math.min(scroll.value, maxScroll)); } else { @@ -143,16 +144,18 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d } return; } -@@ -118,12 +123,23 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -129,17 +134,25 @@ function useChatKeyboard(scrollViewRef, options) { contentOffsetY.value = scroll.value; return; } - contentOffsetY.value = (0, _helpers.computeIOSContentOffset)(relativeScroll, scrollEffective, size.value.height, layout.value.height, inverted, actualTotalPadding); + contentOffsetY.value = (0, _helpers.computeIOSContentOffset)(relativeScroll, scrollEffective, size.value.height, layout.value.height, inverted, actualTotalPadding, adjustedStartInsetCompensation); -+ }, + }, +- onInteractive: () => { + onMove: e => { -+ "worklet"; -+ + "worklet"; + +- isInteractiveDismissal.value = true; + if (freeze.value) { + return; + } @@ -163,6 +166,8 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d "worklet"; - // iOS doesn't need per-frame updates (contentOffset handles it) ++ isInteractiveDismissal.value = true; ++ + if (freeze.value) { + return; + } @@ -170,7 +175,7 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d }, onEnd: e => { "worklet"; -@@ -132,9 +148,10 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -148,9 +161,10 @@ function useChatKeyboard(scrollViewRef, options) { return; } const effective = (0, _helpers.getEffectiveHeight)(e.height, targetKeyboardHeight.value, offset); @@ -183,10 +188,10 @@ index 2073da84b8b2be291aa3181700c2b18a75d0fc56..7ae9bb220ce3cc23c788a79677afdc7d padding, currentHeight, diff --git a/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js b/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js -index 0d50bdfeb7bbc5c14a31ed344f8a690e4fd340b3..e0b73653fd1dd23f0f2e2c85835a3d107e3f666d 100644 +index 54a1c57..19b44fc 100644 --- a/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js +++ b/lib/commonjs/components/KeyboardChatScrollView/useExtraContentPadding/index.js -@@ -29,6 +29,8 @@ function useExtraContentPadding(options) { +@@ -31,6 +31,8 @@ function useExtraContentPadding(options) { extraContentPadding, keyboardPadding, blankSpace, @@ -195,7 +200,7 @@ index 0d50bdfeb7bbc5c14a31ed344f8a690e4fd340b3..e0b73653fd1dd23f0f2e2c85835a3d10 scroll, layout, size, -@@ -68,8 +70,8 @@ function useExtraContentPadding(options) { +@@ -70,8 +72,8 @@ function useExtraContentPadding(options) { } // Compute effective delta considering blankSpace floor @@ -206,7 +211,7 @@ index 0d50bdfeb7bbc5c14a31ed344f8a690e4fd340b3..e0b73653fd1dd23f0f2e2c85835a3d10 const effectiveDelta = currentTotal - previousTotal; if (effectiveDelta === 0) { // blankSpace absorbed the change -@@ -88,10 +90,11 @@ function useExtraContentPadding(options) { +@@ -90,10 +92,11 @@ function useExtraContentPadding(options) { const target = Math.max(scroll.value - effectiveDelta, -currentTotal); scrollToTarget(target); } else { @@ -221,8 +226,9 @@ index 0d50bdfeb7bbc5c14a31ed344f8a690e4fd340b3..e0b73653fd1dd23f0f2e2c85835a3d10 + }, [inverted, keyboardLiftBehavior, adjustedInsetCompensation, adjustedStartInsetCompensation]); } //# sourceMappingURL=index.js.map +\ No newline at end of file diff --git a/lib/module/components/KeyboardChatScrollView/index.js b/lib/module/components/KeyboardChatScrollView/index.js -index 612dd8bd9bd6cc3e30a5acac937ea3383eb1b630..76b858a6590ad0592cc663864ea822db55eaeceb 100644 +index d085394..a57c2f9 100644 --- a/lib/module/components/KeyboardChatScrollView/index.js +++ b/lib/module/components/KeyboardChatScrollView/index.js @@ -1,7 +1,7 @@ @@ -235,7 +241,7 @@ index 612dd8bd9bd6cc3e30a5acac937ea3383eb1b630..76b858a6590ad0592cc663864ea822db import Reanimated from "react-native-reanimated"; import useCombinedRef from "../hooks/useCombinedRef"; import ScrollViewWithBottomPadding from "../ScrollViewWithBottomPadding"; -@@ -19,9 +19,12 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ +@@ -20,9 +20,12 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ offset = 0, extraContentPadding = ZERO_CONTENT_PADDING, blankSpace = ZERO_BLANK_SPACE, @@ -248,7 +254,7 @@ index 612dd8bd9bd6cc3e30a5acac937ea3383eb1b630..76b858a6590ad0592cc663864ea822db onEndVisible, ...rest }, ref) => { -@@ -43,13 +46,17 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ +@@ -44,13 +47,17 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ freeze: freezeSV, offset, blankSpace, @@ -267,7 +273,7 @@ index 612dd8bd9bd6cc3e30a5acac937ea3383eb1b630..76b858a6590ad0592cc663864ea822db scroll, layout, size, -@@ -75,10 +82,26 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ +@@ -81,10 +88,26 @@ const KeyboardChatScrollView = /*#__PURE__*/forwardRef(({ // a bug for you, please open an issue. const totalPadding = useDerivedValue(() => Math.min(layout.value.height, Math.max(blankSpace.value, padding.value + extraContentPadding.value))); @@ -296,7 +302,7 @@ index 612dd8bd9bd6cc3e30a5acac937ea3383eb1b630..76b858a6590ad0592cc663864ea822db onLayoutInternal(e); onLayoutProp === null || onLayoutProp === void 0 || onLayoutProp(e); diff --git a/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js b/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js -index 295e2219b560519b8d033968b5105d1da3e77315..ff7ee3fe0d880c2287a7b70d5ecf952e99357adf 100644 +index 295e221..2f7b87e 100644 --- a/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js +++ b/lib/module/components/KeyboardChatScrollView/useChatKeyboard/helpers.js @@ -193,7 +193,7 @@ export const clampedScrollTarget = (offsetBeforeScroll, keyboardHeight, contentH @@ -319,8 +325,9 @@ index 295e2219b560519b8d033968b5105d1da3e77315..ff7ee3fe0d880c2287a7b70d5ecf952e + return Math.min(Math.max(keyboardHeight + relativeScroll, minScroll), maxScroll); }; //# sourceMappingURL=helpers.js.map +\ No newline at end of file diff --git a/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js b/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js -index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b7217098cba2340 100644 +index 407275d..19427d7 100644 --- a/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js +++ b/lib/module/components/KeyboardChatScrollView/useChatKeyboard/index.ios.js @@ -25,7 +25,9 @@ function useChatKeyboard(scrollViewRef, options) { @@ -334,7 +341,7 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 } = options; const padding = useSharedValue(0); const currentHeight = useSharedValue(0); -@@ -51,6 +53,9 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -52,6 +54,9 @@ function useChatKeyboard(scrollViewRef, options) { targetKeyboardHeight.value = e.height; } const effective = getEffectiveHeight(e.height, targetKeyboardHeight.value, offset); @@ -344,16 +351,16 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 const atEnd = isScrollAtEnd(scroll.value, layout.value.height, size.value.height, inverted); // Scale minimum padding absorption by how much of it is visible. -@@ -59,7 +64,7 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -60,7 +65,7 @@ function useChatKeyboard(scrollViewRef, options) { const visiblePadding = visibleFraction * blankSpace.value; const minimumPaddingAbsorbed = Math.max(0, visiblePadding - extraContentPadding.value); const scrollEffective = getScrollEffective(effective, minimumPaddingAbsorbed); - const actualTotalPadding = Math.max(blankSpace.value, effective + extraContentPadding.value); + const actualTotalPadding = Math.max(blankSpace.value, effective + extraContentPadding.value) + adjustedInsetCompensation; - // persistent mode: when keyboard shrinks, clamp to valid range - if (keyboardLiftBehavior === "persistent" && effective < padding.value) { -@@ -69,8 +74,8 @@ function useChatKeyboard(scrollViewRef, options) { + // `onInteractive` owns the native scroll offset. When its final + // keyboardWillHide event arrives, consume the marker so this +@@ -80,8 +85,8 @@ function useChatKeyboard(scrollViewRef, options) { const maxScroll = Math.max(size.value.height - layout.value.height, 0); contentOffsetY.value = Math.max(-actualTotalPadding, Math.min(scroll.value, maxScroll)); } else { @@ -364,7 +371,7 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 } return; } -@@ -84,8 +89,8 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -95,8 +100,8 @@ function useChatKeyboard(scrollViewRef, options) { const maxScroll = Math.max(size.value.height - layout.value.height, 0); contentOffsetY.value = Math.max(-actualTotalPadding, Math.min(scroll.value, maxScroll)); } else { @@ -375,16 +382,18 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 } return; } -@@ -111,12 +116,23 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -122,17 +127,25 @@ function useChatKeyboard(scrollViewRef, options) { contentOffsetY.value = scroll.value; return; } - contentOffsetY.value = computeIOSContentOffset(relativeScroll, scrollEffective, size.value.height, layout.value.height, inverted, actualTotalPadding); + contentOffsetY.value = computeIOSContentOffset(relativeScroll, scrollEffective, size.value.height, layout.value.height, inverted, actualTotalPadding, adjustedStartInsetCompensation); -+ }, + }, +- onInteractive: () => { + onMove: e => { -+ "worklet"; -+ + "worklet"; + +- isInteractiveDismissal.value = true; + if (freeze.value) { + return; + } @@ -395,6 +404,8 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 "worklet"; - // iOS doesn't need per-frame updates (contentOffset handles it) ++ isInteractiveDismissal.value = true; ++ + if (freeze.value) { + return; + } @@ -402,7 +413,7 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 }, onEnd: e => { "worklet"; -@@ -125,9 +141,10 @@ function useChatKeyboard(scrollViewRef, options) { +@@ -141,9 +154,10 @@ function useChatKeyboard(scrollViewRef, options) { return; } const effective = getEffectiveHeight(e.height, targetKeyboardHeight.value, offset); @@ -415,10 +426,10 @@ index 52943c3a7d6a68fe2094dc1d112c07e6b9d890e4..cc4bfae859191aeb848179028b721709 padding, currentHeight, diff --git a/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js b/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js -index 1afa50987a8d2a5fe3f36b20945efe804d48a873..7b05d0721c50e118cf78c07913b580a31293db77 100644 +index 5885415..6e694fa 100644 --- a/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js +++ b/lib/module/components/KeyboardChatScrollView/useExtraContentPadding/index.js -@@ -23,6 +23,8 @@ function useExtraContentPadding(options) { +@@ -25,6 +25,8 @@ function useExtraContentPadding(options) { extraContentPadding, keyboardPadding, blankSpace, @@ -427,7 +438,7 @@ index 1afa50987a8d2a5fe3f36b20945efe804d48a873..7b05d0721c50e118cf78c07913b580a3 scroll, layout, size, -@@ -62,8 +64,8 @@ function useExtraContentPadding(options) { +@@ -64,8 +66,8 @@ function useExtraContentPadding(options) { } // Compute effective delta considering blankSpace floor @@ -438,7 +449,7 @@ index 1afa50987a8d2a5fe3f36b20945efe804d48a873..7b05d0721c50e118cf78c07913b580a3 const effectiveDelta = currentTotal - previousTotal; if (effectiveDelta === 0) { // blankSpace absorbed the change -@@ -82,11 +84,12 @@ function useExtraContentPadding(options) { +@@ -84,11 +86,12 @@ function useExtraContentPadding(options) { const target = Math.max(scroll.value - effectiveDelta, -currentTotal); scrollToTarget(target); } else { @@ -454,11 +465,12 @@ index 1afa50987a8d2a5fe3f36b20945efe804d48a873..7b05d0721c50e118cf78c07913b580a3 } export { useExtraContentPadding }; //# sourceMappingURL=index.js.map +\ No newline at end of file diff --git a/lib/typescript/components/KeyboardChatScrollView/types.d.ts b/lib/typescript/components/KeyboardChatScrollView/types.d.ts -index a036b431f03efb9d5379527c17db6fce62bfee09..5e56bf7edec9161698a745e8e6292bfccd68d3db 100644 +index eba1514..6597d80 100644 --- a/lib/typescript/components/KeyboardChatScrollView/types.d.ts +++ b/lib/typescript/components/KeyboardChatScrollView/types.d.ts -@@ -86,6 +86,10 @@ export type KeyboardChatScrollViewProps = { +@@ -88,6 +88,10 @@ export type KeyboardChatScrollViewProps = { * Default is `undefined` (equivalent to `0` — no minimum floor). */ blankSpace?: SharedValue; @@ -470,7 +482,7 @@ index a036b431f03efb9d5379527c17db6fce62bfee09..5e56bf7edec9161698a745e8e6292bfc * Fires whenever the effective content inset changes — the static `contentInset` * prop combined with the dynamic keyboard-driven padding. diff --git a/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts b/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts -index 2b51cc4737b4a05b5396da31e67e54177f43c498..3acec1fbddee6227915590a6c8d449757cb4d7b2 100644 +index 2b51cc4..3acec1f 100644 --- a/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts +++ b/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/helpers.d.ts @@ -129,4 +129,4 @@ export declare const clampedScrollTarget: (offsetBeforeScroll: number, keyboardH @@ -480,7 +492,7 @@ index 2b51cc4737b4a05b5396da31e67e54177f43c498..3acec1fbddee6227915590a6c8d44975 -export declare const computeIOSContentOffset: (relativeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number, inverted: boolean, totalPaddingForMaxScroll?: number) => number; +export declare const computeIOSContentOffset: (relativeScroll: number, keyboardHeight: number, contentHeight: number, layoutHeight: number, inverted: boolean, totalPaddingForMaxScroll?: number, startInsetCompensation?: number) => number; diff --git a/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts b/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts -index aff9b5a8dbc2464546396437eaf6c5ae955b9f29..fdd83953271123be6caefaa786c469f0d92cce2b 100644 +index aff9b5a..fdd8395 100644 --- a/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts +++ b/lib/typescript/components/KeyboardChatScrollView/useChatKeyboard/types.d.ts @@ -9,6 +9,10 @@ type UseChatKeyboardOptions = { @@ -495,7 +507,7 @@ index aff9b5a8dbc2464546396437eaf6c5ae955b9f29..fdd83953271123be6caefaa786c469f0 type UseChatKeyboardReturn = { /** Extra scrollable space (= keyboard height). Used as contentInset on iOS, contentInsetBottom/contentInsetTop on Android. */ diff --git a/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts b/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts -index ec73f70544a062fbecfc1d8be92d839d3e0bea6f..45b387446587fd3e611fa02a01534bb5d9fa6bbd 100644 +index ec73f70..45b3874 100644 --- a/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts +++ b/lib/typescript/components/KeyboardChatScrollView/useExtraContentPadding/index.d.ts @@ -8,6 +8,10 @@ type UseExtraContentPaddingOptions = { @@ -510,7 +522,7 @@ index ec73f70544a062fbecfc1d8be92d839d3e0bea6f..45b387446587fd3e611fa02a01534bb5 scroll: SharedValue; /** Visible viewport dimensions. */ diff --git a/src/components/KeyboardChatScrollView/index.tsx b/src/components/KeyboardChatScrollView/index.tsx -index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d029c8ecc10 100644 +index 554b38c..725d546 100644 --- a/src/components/KeyboardChatScrollView/index.tsx +++ b/src/components/KeyboardChatScrollView/index.tsx @@ -1,7 +1,9 @@ @@ -524,7 +536,7 @@ index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d02 useAnimatedRef, useAnimatedStyle, useDerivedValue, -@@ -35,9 +37,12 @@ const KeyboardChatScrollView = forwardRef< +@@ -39,9 +41,12 @@ const KeyboardChatScrollView: React.ForwardRefExoticComponent< offset = 0, extraContentPadding = ZERO_CONTENT_PADDING, blankSpace = ZERO_BLANK_SPACE, @@ -537,7 +549,7 @@ index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d02 onEndVisible, ...rest }, -@@ -64,6 +69,8 @@ const KeyboardChatScrollView = forwardRef< +@@ -68,6 +73,8 @@ const KeyboardChatScrollView: React.ForwardRefExoticComponent< offset, blankSpace, extraContentPadding, @@ -546,7 +558,7 @@ index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d02 }); useExtraContentPadding({ -@@ -71,6 +78,8 @@ const KeyboardChatScrollView = forwardRef< +@@ -75,6 +82,8 @@ const KeyboardChatScrollView: React.ForwardRefExoticComponent< extraContentPadding, keyboardPadding: padding, blankSpace, @@ -555,7 +567,7 @@ index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d02 scroll, layout, size, -@@ -102,13 +111,40 @@ const KeyboardChatScrollView = forwardRef< +@@ -112,13 +121,40 @@ const KeyboardChatScrollView: React.ForwardRefExoticComponent< ), ); @@ -602,10 +614,10 @@ index 03f5f74e9aaaabc75db1c01643a655ee4fdfa5f2..277a1ecada428ffbae517d6edc720d02 (e: LayoutChangeEvent) => { onLayoutInternal(e); diff --git a/src/components/KeyboardChatScrollView/types.ts b/src/components/KeyboardChatScrollView/types.ts -index dd222b57bc7a71729524670bad3812f30920bd73..7be71b5460eb143ddf460ce5c87b843c66bfb2cd 100644 +index b7c98c8..e1012a8 100644 --- a/src/components/KeyboardChatScrollView/types.ts +++ b/src/components/KeyboardChatScrollView/types.ts -@@ -90,6 +90,17 @@ export type KeyboardChatScrollViewProps = { +@@ -93,6 +93,17 @@ export type KeyboardChatScrollViewProps = { * Default is `undefined` (equivalent to `0` — no minimum floor). */ blankSpace?: SharedValue; @@ -624,7 +636,7 @@ index dd222b57bc7a71729524670bad3812f30920bd73..7be71b5460eb143ddf460ce5c87b843c * Fires whenever the effective content inset changes — the static `contentInset` * prop combined with the dynamic keyboard-driven padding. diff --git a/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts b/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts -index 37eacd10857cd70c51b3468c4b466e4959d0a415..3d77ab27c614f44b64da8270823942cb670b097b 100644 +index 37eacd1..3d77ab2 100644 --- a/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts +++ b/src/components/KeyboardChatScrollView/useChatKeyboard/helpers.ts @@ -245,6 +245,7 @@ export const computeIOSContentOffset = ( @@ -653,7 +665,7 @@ index 37eacd10857cd70c51b3468c4b466e4959d0a415..3d77ab27c614f44b64da8270823942cb + ); }; diff --git a/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts b/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts -index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605633192ed 100644 +index 129a74b..168ce1a 100644 --- a/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts +++ b/src/components/KeyboardChatScrollView/useChatKeyboard/index.ios.ts @@ -43,6 +43,8 @@ function useChatKeyboard( @@ -665,7 +677,7 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 } = options; const padding = useSharedValue(0); -@@ -79,6 +81,10 @@ function useChatKeyboard( +@@ -80,6 +82,10 @@ function useChatKeyboard( offset, ); @@ -676,7 +688,7 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 const atEnd = isScrollAtEnd( scroll.value, layout.value.height, -@@ -104,10 +110,12 @@ function useChatKeyboard( +@@ -105,10 +111,12 @@ function useChatKeyboard( effective, minimumPaddingAbsorbed, ); @@ -691,9 +703,9 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 + Math.max(blankSpace.value, effective + extraContentPadding.value) + + adjustedInsetCompensation; - // persistent mode: when keyboard shrinks, clamp to valid range - if ( -@@ -130,11 +138,11 @@ function useChatKeyboard( + // `onInteractive` owns the native scroll offset. When its final + // keyboardWillHide event arrives, consume the marker so this +@@ -142,11 +150,11 @@ function useChatKeyboard( } else { const maxScroll = Math.max( size.value.height - layout.value.height + actualTotalPadding, @@ -707,7 +719,7 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 Math.min(scroll.value, maxScroll), ); } -@@ -165,11 +173,11 @@ function useChatKeyboard( +@@ -177,11 +185,11 @@ function useChatKeyboard( } else { const maxScroll = Math.max( size.value.height - layout.value.height + actualTotalPadding, @@ -721,18 +733,18 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 Math.min(scroll.value, maxScroll), ); } -@@ -219,12 +227,34 @@ function useChatKeyboard( +@@ -231,17 +239,36 @@ function useChatKeyboard( layout.value.height, inverted, actualTotalPadding, + adjustedStartInsetCompensation, ); }, -- onMove: () => { +- onInteractive: () => { + onMove: (e) => { "worklet"; -- // iOS doesn't need per-frame updates (contentOffset handles it) +- isInteractiveDismissal.value = true; + if (freeze.value) { + return; + } @@ -742,9 +754,13 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 + targetKeyboardHeight.value, + offset, + ); -+ }, + }, +- onMove: () => { + onInteractive: (e) => { -+ "worklet"; + "worklet"; + +- // iOS doesn't need per-frame updates (contentOffset handles it) ++ isInteractiveDismissal.value = true; + + if (freeze.value) { + return; @@ -758,7 +774,7 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 }, onEnd: (e) => { "worklet"; -@@ -239,10 +269,18 @@ function useChatKeyboard( +@@ -256,10 +283,18 @@ function useChatKeyboard( offset, ); @@ -779,7 +795,7 @@ index 560df54bae1a8c41a2e9ac0e2a8d2fd9b843968a..c375a8c4cc889c2fc2c0c1034788c605 return { diff --git a/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts b/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts -index 02abf5cd9490900826678175462b234e07e30e92..4ee0ddd65e0b105568ab43b73997af4be8adae00 100644 +index 02abf5c..4ee0ddd 100644 --- a/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts +++ b/src/components/KeyboardChatScrollView/useChatKeyboard/types.ts @@ -11,6 +11,10 @@ type UseChatKeyboardOptions = { @@ -794,7 +810,7 @@ index 02abf5cd9490900826678175462b234e07e30e92..4ee0ddd65e0b105568ab43b73997af4b type UseChatKeyboardReturn = { diff --git a/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts b/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts -index 833acbe78f1b1245251ddd3431d6546decdd0ade..8f7c10cb6ab392f10df4ca43549b89c25844f0b8 100644 +index c9c93f3..76a201d 100644 --- a/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts +++ b/src/components/KeyboardChatScrollView/useExtraContentPadding/index.ts @@ -16,6 +16,10 @@ type UseExtraContentPaddingOptions = { @@ -808,7 +824,7 @@ index 833acbe78f1b1245251ddd3431d6546decdd0ade..8f7c10cb6ab392f10df4ca43549b89c2 /** Current vertical scroll offset. */ scroll: SharedValue; /** Visible viewport dimensions. */ -@@ -49,6 +53,8 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { +@@ -51,6 +55,8 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { extraContentPadding, keyboardPadding, blankSpace, @@ -817,7 +833,7 @@ index 833acbe78f1b1245251ddd3431d6546decdd0ade..8f7c10cb6ab392f10df4ca43549b89c2 scroll, layout, size, -@@ -97,14 +103,12 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { +@@ -99,14 +105,12 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { } // Compute effective delta considering blankSpace floor @@ -838,7 +854,7 @@ index 833acbe78f1b1245251ddd3431d6546decdd0ade..8f7c10cb6ab392f10df4ca43549b89c2 const effectiveDelta = currentTotal - previousTotal; if (effectiveDelta === 0) { -@@ -137,16 +141,25 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { +@@ -139,16 +143,25 @@ function useExtraContentPadding(options: UseExtraContentPaddingOptions): void { scrollToTarget(target); } else { diff --git a/patches/react-native-nitro-modules@0.35.9.patch b/patches/react-native-nitro-modules@0.35.9.patch index d70069dd4d1a..a58d3d5f97ee 100644 --- a/patches/react-native-nitro-modules@0.35.9.patch +++ b/patches/react-native-nitro-modules@0.35.9.patch @@ -1,3 +1,19 @@ +diff --git a/ios/turbomodule/NativeNitroModules+NewArch.mm b/ios/turbomodule/NativeNitroModules+NewArch.mm +--- a/ios/turbomodule/NativeNitroModules+NewArch.mm ++++ b/ios/turbomodule/NativeNitroModules+NewArch.mm +@@ -34,6 +34,12 @@ + } + RCT_EXPORT_MODULE(NitroModules) + ++// RN 0.87+ passes the CallInvoker directly when installing JSI bindings. ++- (void)installJSIBindingsWithRuntime:(jsi::Runtime&)runtime callInvoker:(const std::shared_ptr&)callInvoker { ++ _callInvoker = callInvoker; ++ [self installJSIBindingsWithRuntime:runtime]; ++} ++ + - (void)installJSIBindingsWithRuntime:(jsi::Runtime&)runtime { + // 1. Get CallInvoker we cached statically + std::shared_ptr callInvoker = _callInvoker.lock(); diff --git a/package.json b/package.json index 4e4366fb9d05a6c250acfc62e79487475d8ac05b..200e4680d77cbb4f14d22eb986efde1275a0d3e8 100644 --- a/package.json diff --git a/patches/react-native-reanimated@4.5.5.patch b/patches/react-native-reanimated@4.5.5.patch deleted file mode 100644 index c0cc66e40789..000000000000 --- a/patches/react-native-reanimated@4.5.5.patch +++ /dev/null @@ -1,69 +0,0 @@ -diff --git a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h -index 20d042b00e4655a6647eff1a9a0890fae7e45175..fd08d36fd6c1f79adcfa0dc675420e42a9815d25 100644 ---- a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h -+++ b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxyCommon.h -@@ -22,6 +22,7 @@ struct LayoutAnimation { - Tag parentTag; - std::optional opacity; - bool isViewAlreadyMounted = false; -+ bool isExitingWhenSettled = false; - int count = 1; - LayoutAnimation &operator=(const LayoutAnimation &other) = default; - -diff --git a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp -index 0f08622518910486bb724b664e0a5dd692470b18..9f71dbc301e77656ab0c5dc453ade03eea7649f8 100644 ---- a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp -+++ b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Experimental.cpp -@@ -353,6 +353,7 @@ std::optional LayoutAnimationsProxy_Experimental::endLayoutAnimation( - if (--layoutAnimation.count > 0) { - return {}; - } -+ layoutAnimation.isExitingWhenSettled = shouldRemove; - maybeSettledAnimationTags_.insert(tag); - auto surfaceId = layoutAnimation.finalView.surfaceId; - -@@ -478,7 +479,8 @@ void LayoutAnimationsProxy_Experimental::addOngoingAnimations(SurfaceId surfaceI - - const auto layoutAnimationIt = layoutAnimations_.find(tag); - -- if (layoutAnimationIt == layoutAnimations_.end() || layoutAnimationIt->second.isSettled()) { -+ if (layoutAnimationIt == layoutAnimations_.end() || -+ (layoutAnimationIt->second.isSettled() && layoutAnimationIt->second.isExitingWhenSettled)) { - continue; - } - -@@ -635,6 +637,8 @@ void LayoutAnimationsProxy_Experimental::maybeCancelAnimation(const int tag) con - } - if (layoutAnimationIt->second.isSettled()) { - // Already settled - cleanupAnimations will erase it together with its updateMap entry. -+ // Do not flush a pending Update after the caller queues this view for removal. -+ layoutAnimationIt->second.isExitingWhenSettled = true; - return; - } - layoutAnimations_.erase(layoutAnimationIt); -diff --git a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp -index f9711f4eb6185ea99e08280ff90edd45e4152e12..ca812666ca54ec55d9d4409910b21ae97c721f2f 100644 ---- a/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp -+++ b/Common/cpp/reanimated/LayoutAnimations/LayoutAnimationsProxy_Legacy.cpp -@@ -228,6 +228,7 @@ std::optional LayoutAnimationsProxy_Legacy::endLayoutAnimation(int ta - if (--layoutAnimation.count > 0) { - return {}; - } -+ layoutAnimation.isExitingWhenSettled = shouldRemove; - maybeSettledAnimationTags_.insert(tag); - auto surfaceId = layoutAnimation.finalView.surfaceId; - -@@ -531,12 +532,7 @@ void LayoutAnimationsProxy_Legacy::addOngoingAnimations(SurfaceId surfaceId, Sha - auto layoutAnimationIt = layoutAnimations_.find(tag); - - if (layoutAnimationIt == layoutAnimations_.end() || -- // A settled animation is normally cleaned up without applying further -- // updates. The exception is a flaky entering animation whose opacity was -- // never restored (the view wasn't mounted in time) - we still need to -- // apply that pending opacity, otherwise the view stays invisible. Only -- // entering animations carry an opacity value. -- (layoutAnimationIt->second.isSettled() && !layoutAnimationIt->second.opacity.has_value())) { -+ (layoutAnimationIt->second.isSettled() && layoutAnimationIt->second.isExitingWhenSettled)) { - continue; - } - diff --git a/patches/react-native-screens@4.26.2.patch b/patches/react-native-screens@4.28.0.patch similarity index 94% rename from patches/react-native-screens@4.26.2.patch rename to patches/react-native-screens@4.28.0.patch index 9212cfc7b0ff..8b07155c5afe 100644 --- a/patches/react-native-screens@4.26.2.patch +++ b/patches/react-native-screens@4.28.0.patch @@ -1,5 +1,5 @@ diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt -index fa1b77317f609983ae2434764174072e51130550..270c81c90971b0ff3038b999973dd4d128a9d140 100644 +index fa1b773..270c81c 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderConfigViewManager.kt @@ -124,6 +124,34 @@ class ScreenStackHeaderConfigViewManager : @@ -38,7 +38,7 @@ index fa1b77317f609983ae2434764174072e51130550..270c81c90971b0ff3038b999973dd4d1 config: ScreenStackHeaderConfig, titleFontFamily: String?, diff --git a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt -index 64f14f0c5ade16eb9519b8780d4ce013f88fbd3a..6cb1d69f97a95759c662a6006a9626925d9fefd9 100644 +index 64f14f0..6cb1d69 100644 --- a/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt +++ b/android/src/main/java/com/swmansion/rnscreens/ScreenStackHeaderSubviewManager.kt @@ -47,6 +47,12 @@ class ScreenStackHeaderSubviewManager : @@ -55,7 +55,7 @@ index 64f14f0c5ade16eb9519b8780d4ce013f88fbd3a..6cb1d69f97a95759c662a6006a962692 // however we must override their setters override fun setSynchronousShadowStateUpdatesEnabled( diff --git a/ios/RNSBarButtonItem.h b/ios/RNSBarButtonItem.h -index a26d1254eafd89268f65d968988cf6a3b8c1e457..62eea42ac26c532801189556c5f51012c3df3a52 100644 +index a26d125..62eea42 100644 --- a/ios/RNSBarButtonItem.h +++ b/ios/RNSBarButtonItem.h @@ -15,6 +15,10 @@ typedef void (^RNSBarButtonMenuItemAction)(NSString *menuId); @@ -70,7 +70,7 @@ index a26d1254eafd89268f65d968988cf6a3b8c1e457..62eea42ac26c532801189556c5f51012 @end diff --git a/ios/RNSBarButtonItem.mm b/ios/RNSBarButtonItem.mm -index 0eb1f09dee82edd99e3e614938233db5cdeaebfe..73298f10807520970f625e166d7f5dd1338206f1 100644 +index 76a39d4..15bd5a9 100644 --- a/ios/RNSBarButtonItem.mm +++ b/ios/RNSBarButtonItem.mm @@ -110,6 +110,58 @@ - (instancetype)initWithConfig:(NSDictionary *)dict @@ -132,8 +132,58 @@ index 0eb1f09dee82edd99e3e614938233db5cdeaebfe..73298f10807520970f625e166d7f5dd1 #if !TARGET_OS_TV || __TV_OS_VERSION_MAX_ALLOWED >= 170000 if (@available(tvOS 17.0, *)) { +diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm +index c233036..0c2db42 100644 +--- a/ios/RNSScreenStack.mm ++++ b/ios/RNSScreenStack.mm +@@ -1076,6 +1076,15 @@ - (BOOL)scrollViewHasHorizontalPart:(UIScrollView *)scrollView + return scrollView.contentSize.width > scrollView.frame.size.width; + } + ++// Whether a horizontally scrollable ScrollView is resting at its leading edge, so a ++// pan in the back-gesture direction has nothing left to scroll. Checked in the ++// ScrollView's own coordinate space: React Native mirrors the view for RTL layout, ++// which keeps the leading edge at the minimum content offset in both directions. ++- (BOOL)scrollViewIsAtLeadingEdge:(UIScrollView *)scrollView ++{ ++ return scrollView.contentOffset.x <= -scrollView.adjustedContentInset.left + 1.0; ++} ++ + // Custom method for compatibility with iOS < 13.4 + // RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers: + // RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer +@@ -1169,9 +1178,11 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer + if (gestureRecognizer == _controller.interactiveContentPopGestureRecognizer && + [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) { + // ScrollView should take precedence when scrolling horizontally (it should be required to fail). +- // However, if it does not allow for horizontal scrolling, there should be no such restriction, ++ // However, if it does not allow for horizontal scrolling, or is already resting at its leading ++ // edge so a back swipe has nothing left to scroll, there should be no such restriction, + // and swiping horizontally should dismiss the screen. +- return [self scrollViewHasHorizontalPart:static_cast(otherGestureRecognizer.view)]; ++ UIScrollView *scrollView = static_cast(otherGestureRecognizer.view); ++ return [self scrollViewHasHorizontalPart:scrollView] && ![self scrollViewIsAtLeadingEdge:scrollView]; + } + } + +@@ -1191,6 +1202,15 @@ - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer + // gestureRecognizer:shouldRequireFailureOfGestureRecognizer + isEdgeSwipeGestureRecognizer = + isEdgeSwipeGestureRecognizer && gestureRecognizer != _controller.interactiveContentPopGestureRecognizer; ++ ++ // The exception is a horizontal ScrollView resting at its leading edge: its pan recognizer would ++ // still begin (and merely bounce) on a back swipe, so it must yield to the pop gesture the same ++ // way plain content does. ++ if (gestureRecognizer == _controller.interactiveContentPopGestureRecognizer && ++ [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) { ++ UIScrollView *scrollView = static_cast(otherGestureRecognizer.view); ++ return [self scrollViewHasHorizontalPart:scrollView] && [self scrollViewIsAtLeadingEdge:scrollView]; ++ } + } + #endif // check for iOS >= 26 + diff --git a/ios/RNSScreenStackHeaderConfig.h b/ios/RNSScreenStackHeaderConfig.h -index 8a41697223f6c4b5cb2dd6d450fc58cbb3b27536..309ba2f762068dcf452c172f7c7cbf2a55d03cb2 100644 +index 8a41697..309ba2f 100644 --- a/ios/RNSScreenStackHeaderConfig.h +++ b/ios/RNSScreenStackHeaderConfig.h @@ -23,6 +23,8 @@ @@ -159,7 +209,7 @@ index 8a41697223f6c4b5cb2dd6d450fc58cbb3b27536..309ba2f762068dcf452c172f7c7cbf2a NS_ASSUME_NONNULL_END diff --git a/ios/RNSScreenStackHeaderConfig.mm b/ios/RNSScreenStackHeaderConfig.mm -index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab60e185033 100644 +index a54cb63..4ff30b3 100644 --- a/ios/RNSScreenStackHeaderConfig.mm +++ b/ios/RNSScreenStackHeaderConfig.mm @@ -24,11 +24,46 @@ @@ -760,7 +810,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 + BOOL reuseToolbarItems = navctr.topViewController == vc && + navctr.isToolbarHidden == (toolbarConfigsKey.count == 0) && + [objc_getAssociatedObject(navitem, &RNSAppliedToolbarConfigsKey) isEqual:toolbarCacheKey]; -+ if (!reuseToolbarItems) { ++ if (navctr.topViewController == vc && !reuseToolbarItems) { + NSArray *toolbarItems = [config barButtonItemsFromConfigs:navigationToolbarConfigs + withCurrentItems:@[] + navigationItem:navitem @@ -778,7 +828,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 // Setting navigation bar visibility is split to mitigate iOS 26 bug with bar button items // (setting nav bar visibility should be done after `navitem.*BarButtonItems`). -@@ -784,6 +1289,8 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * +@@ -784,6 +1298,8 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * - (NSArray *)barButtonItemsFromConfigs:(NSArray *> *)dicts withCurrentItems:(NSArray *)currentItems @@ -787,7 +837,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 { if (dicts.count == 0) { return currentItems; -@@ -792,7 +1299,200 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * +@@ -792,7 +1308,200 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * [items addObjectsFromArray:currentItems]; for (NSUInteger i = 0; i < dicts.count; i++) { NSDictionary *dict = dicts[i]; @@ -989,7 +1039,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 RNSBarButtonItem *item = [[RNSBarButtonItem alloc] initWithConfig:dict action:^(NSString *buttonId) { auto eventEmitter = std::static_pointer_cast( -@@ -814,19 +1514,23 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * +@@ -814,19 +1523,23 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * } imageLoader:_imageLoader]; NSNumber *index = dict[@"index"]; @@ -1019,7 +1069,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 [items insertObject:item atIndex:index.integerValue]; } else { [items addObject:item]; -@@ -836,6 +1540,47 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * +@@ -836,6 +1549,47 @@ - (void)applySemanticContentAttributeIfNeededToNavCtrl:(UINavigationController * return items; } @@ -1067,7 +1117,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 RNS_IGNORE_SUPER_CALL_BEGIN - (void)insertReactSubview:(RNSScreenStackHeaderSubview *)subview atIndex:(NSInteger)atIndex { -@@ -1023,6 +1768,8 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: +@@ -1025,6 +1779,8 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: } _title = RCTNSStringFromStringNilIfEmpty(newScreenProps.title); @@ -1076,7 +1126,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 if (newScreenProps.titleFontFamily != oldScreenProps.titleFontFamily) { _titleFontFamily = RCTNSStringFromStringNilIfEmpty(newScreenProps.titleFontFamily); } -@@ -1048,6 +1795,7 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: +@@ -1050,6 +1806,7 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: _disableBackButtonMenu = newScreenProps.disableBackButtonMenu; _backButtonDisplayMode = [RNSConvert UINavigationItemBackButtonDisplayModeFromCppEquivalent:newScreenProps.backButtonDisplayMode]; @@ -1084,7 +1134,7 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 if (newScreenProps.userInterfaceStyle != oldScreenProps.userInterfaceStyle) { _userInterfaceStyle = [RNSConvert UIUserInterfaceStyleFromCppEquivalent:newScreenProps.userInterfaceStyle]; -@@ -1094,6 +1842,30 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: +@@ -1096,6 +1853,30 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: _headerRightBarButtonItems = array; } @@ -1115,57 +1165,8 @@ index 1c844846a5c66e31cfa530ca462774d2fb6bbea1..a60b96b44e85d3f4b29dc0d190b95ab6 [self updateViewControllerIfNeeded]; if (needsNavigationControllerLayout) { -diff --git a/ios/RNSScreenStack.mm b/ios/RNSScreenStack.mm ---- a/ios/RNSScreenStack.mm -+++ b/ios/RNSScreenStack.mm -@@ -1074,6 +1074,15 @@ RNS_IGNORE_SUPER_CALL_END - return scrollView.contentSize.width > scrollView.frame.size.width; - } - -+// Whether a horizontally scrollable ScrollView is resting at its leading edge, so a -+// pan in the back-gesture direction has nothing left to scroll. Checked in the -+// ScrollView's own coordinate space: React Native mirrors the view for RTL layout, -+// which keeps the leading edge at the minimum content offset in both directions. -+- (BOOL)scrollViewIsAtLeadingEdge:(UIScrollView *)scrollView -+{ -+ return scrollView.contentOffset.x <= -scrollView.adjustedContentInset.left + 1.0; -+} -+ - // Custom method for compatibility with iOS < 13.4 - // RNSScreenStackView is a UIGestureRecognizerDelegate for three types of gesture recognizers: - // RNSPanGestureRecognizer, RNSScreenEdgeGestureRecognizer, _UIParallaxTransitionPanGestureRecognizer -@@ -1167,9 +1176,11 @@ RNS_IGNORE_SUPER_CALL_END - if (gestureRecognizer == _controller.interactiveContentPopGestureRecognizer && - [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) { - // ScrollView should take precedence when scrolling horizontally (it should be required to fail). -- // However, if it does not allow for horizontal scrolling, there should be no such restriction, -+ // However, if it does not allow for horizontal scrolling, or is already resting at its leading -+ // edge so a back swipe has nothing left to scroll, there should be no such restriction, - // and swiping horizontally should dismiss the screen. -- return [self scrollViewHasHorizontalPart:static_cast(otherGestureRecognizer.view)]; -+ UIScrollView *scrollView = static_cast(otherGestureRecognizer.view); -+ return [self scrollViewHasHorizontalPart:scrollView] && ![self scrollViewIsAtLeadingEdge:scrollView]; - } - } - -@@ -1189,6 +1200,15 @@ RNS_IGNORE_SUPER_CALL_END - // gestureRecognizer:shouldRequireFailureOfGestureRecognizer - isEdgeSwipeGestureRecognizer = - isEdgeSwipeGestureRecognizer && gestureRecognizer != _controller.interactiveContentPopGestureRecognizer; -+ -+ // The exception is a horizontal ScrollView resting at its leading edge: its pan recognizer would -+ // still begin (and merely bounce) on a back swipe, so it must yield to the pop gesture the same -+ // way plain content does. -+ if (gestureRecognizer == _controller.interactiveContentPopGestureRecognizer && -+ [self isScrollViewPanGestureRecognizer:otherGestureRecognizer]) { -+ UIScrollView *scrollView = static_cast(otherGestureRecognizer.view); -+ return [self scrollViewHasHorizontalPart:scrollView] && [self scrollViewIsAtLeadingEdge:scrollView]; -+ } - } - #endif // check for iOS >= 26 - diff --git a/ios/RNSScreenStackHeaderSubview.mm b/ios/RNSScreenStackHeaderSubview.mm -index add33c4807e038dcd846f6c72b2fc472ded02809..489afa5fa2da09c1ec6986d1832b58bb595396ae 100644 +index add33c4..489afa5 100644 --- a/ios/RNSScreenStackHeaderSubview.mm +++ b/ios/RNSScreenStackHeaderSubview.mm @@ -20,7 +20,9 @@ @implementation RNSScreenStackHeaderSubview { @@ -1178,7 +1179,7 @@ index add33c4807e038dcd846f6c72b2fc472ded02809..489afa5fa2da09c1ec6986d1832b58bb } #pragma mark - Common -@@ -102,5 +104,24 @@ - (void)updateShadowStateWithFrame:(CGRect)frame +@@ -102,6 +104,25 @@ - (void)updateShadowStateWithFrame:(CGRect)frame - (void)layoutSubviews { [super layoutSubviews]; @@ -1203,6 +1204,7 @@ index add33c4807e038dcd846f6c72b2fc472ded02809..489afa5fa2da09c1ec6986d1832b58bb +#endif [self updateShadowStateInContextOfAncestorView:[self findNavigationBar]]; } + @@ -124,6 +145,7 @@ - (void)updateProps:(react::Props::Shared const &)props oldProps:(react::Props:: const auto &newHeaderSubviewProps = *std::static_pointer_cast(props); @@ -1251,10 +1253,10 @@ index add33c4807e038dcd846f6c72b2fc472ded02809..489afa5fa2da09c1ec6986d1832b58bb // Needed because of this: https://github.com/facebook/react-native/pull/37274 diff --git a/lib/commonjs/components/ScreenStackHeaderConfig.js b/lib/commonjs/components/ScreenStackHeaderConfig.js -index 8c509f2657105cfd86448347c1a01fb73651ff9e..e668e089a1788973cb122a150be7846364a2a2cf 100644 +index 6e68cd1..9e09485 100644 --- a/lib/commonjs/components/ScreenStackHeaderConfig.js +++ b/lib/commonjs/components/ScreenStackHeaderConfig.js -@@ -26,17 +26,42 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ +@@ -31,17 +31,42 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ } = (0, _EdgeInsetApplicationContext.useEdgeInsetApplication)(!props.hidden, props.disableTopInsetApplication ?? false, props.disableLeftInsetApplication ?? false, props.disableRightInsetApplication ?? false, props.disableBottomInsetApplication ?? false); const { headerLeftBarButtonItems, @@ -1300,7 +1302,7 @@ index 8c509f2657105cfd86448347c1a01fb73651ff9e..e668e089a1788973cb122a150be78463 } } : undefined; -@@ -59,7 +84,7 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ +@@ -64,7 +89,7 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ }; // Check each bar-button item with a menu @@ -1309,7 +1311,7 @@ index 8c509f2657105cfd86448347c1a01fb73651ff9e..e668e089a1788973cb122a150be78463 for (const item of allItems) { if (item && item.type === 'menu' && item.menu) { const action = findInMenu(item.menu, event.nativeEvent.menuId); -@@ -67,6 +92,15 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ +@@ -72,6 +97,15 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ action.onPress(); return; } @@ -1325,7 +1327,7 @@ index 8c509f2657105cfd86448347c1a01fb73651ff9e..e668e089a1788973cb122a150be78463 } } } : undefined; -@@ -74,6 +108,8 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ +@@ -79,6 +113,8 @@ const ScreenStackHeaderConfig = exports.ScreenStackHeaderConfig = /*#__PURE__*/_ userInterfaceStyle: props.experimental_userInterfaceStyle, headerLeftBarButtonItems: preparedHeaderLeftBarButtonItems, headerRightBarButtonItems: preparedHeaderRightBarButtonItems, @@ -1335,19 +1337,19 @@ index 8c509f2657105cfd86448347c1a01fb73651ff9e..e668e089a1788973cb122a150be78463 onPressHeaderBarButtonMenuItem: onPressHeaderBarButtonMenuItem, ref: ref, diff --git a/lib/commonjs/components/helpers/prepareHeaderBarButtonItems.js b/lib/commonjs/components/helpers/prepareHeaderBarButtonItems.js -index ab93f62e4a7049d63c6681cecbd6cf8b1d07ce10..9dca2ab640e92161eb647b819a989acd0d41d9fe 100644 +index 589b6cc..b584624 100644 --- a/lib/commonjs/components/helpers/prepareHeaderBarButtonItems.js +++ b/lib/commonjs/components/helpers/prepareHeaderBarButtonItems.js -@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", { - }); - exports.prepareHeaderBarButtonItems = void 0; - var _reactNative = require("react-native"); +@@ -8,7 +8,7 @@ var _reactNative = require("react-native"); + // Local nominal type so declaration emit doesn't resolve the RN alias down to + // the non-public `types_generated/.../AssetSourceResolver#ResolvedAssetSource`. + -const prepareMenu = (menu, index, side, path = '') => { +const prepareMenu = (menu, index, placement, path = '') => { return { ...menu, items: menu.items.map((menuItem, menuIndex) => { -@@ -26,7 +26,7 @@ const prepareMenu = (menu, index, side, path = '') => { +@@ -29,7 +29,7 @@ const prepareMenu = (menu, index, side, path = '') => { xcassetName, imageSource, templateSource, @@ -1356,7 +1358,7 @@ index ab93f62e4a7049d63c6681cecbd6cf8b1d07ce10..9dca2ab640e92161eb647b819a989acd }; } return { -@@ -35,16 +35,40 @@ const prepareMenu = (menu, index, side, path = '') => { +@@ -38,16 +38,40 @@ const prepareMenu = (menu, index, side, path = '') => { xcassetName, imageSource, templateSource, @@ -1400,7 +1402,7 @@ index ab93f62e4a7049d63c6681cecbd6cf8b1d07ce10..9dca2ab640e92161eb647b819a989acd let imageSource, templateSource; if (item.icon?.type === 'imageSource') { imageSource = _reactNative.Image.resolveAssetSource(item.icon.imageSource); -@@ -77,17 +101,17 @@ const prepareHeaderBarButtonItems = (barButtonItems, side) => { +@@ -80,17 +104,17 @@ const prepareHeaderBarButtonItems = (barButtonItems, side) => { if (item.type === 'button') { return { ...processedItem, @@ -1423,10 +1425,10 @@ index ab93f62e4a7049d63c6681cecbd6cf8b1d07ce10..9dca2ab640e92161eb647b819a989acd //# sourceMappingURL=prepareHeaderBarButtonItems.js.map \ No newline at end of file diff --git a/lib/module/components/ScreenStackHeaderConfig.js b/lib/module/components/ScreenStackHeaderConfig.js -index 68e3ba6a78314aba908d07098bb6982d11e6ee80..db5d17bfdac19ed3e664b55b6a73ce49766ac7c5 100644 +index 242898c..7cebaa3 100644 --- a/lib/module/components/ScreenStackHeaderConfig.js +++ b/lib/module/components/ScreenStackHeaderConfig.js -@@ -22,17 +22,42 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref +@@ -27,17 +27,42 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref } = useEdgeInsetApplication(!props.hidden, props.disableTopInsetApplication ?? false, props.disableLeftInsetApplication ?? false, props.disableRightInsetApplication ?? false, props.disableBottomInsetApplication ?? false); const { headerLeftBarButtonItems, @@ -1472,7 +1474,7 @@ index 68e3ba6a78314aba908d07098bb6982d11e6ee80..db5d17bfdac19ed3e664b55b6a73ce49 } } : undefined; -@@ -55,7 +80,7 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref +@@ -60,7 +85,7 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref }; // Check each bar-button item with a menu @@ -1481,7 +1483,7 @@ index 68e3ba6a78314aba908d07098bb6982d11e6ee80..db5d17bfdac19ed3e664b55b6a73ce49 for (const item of allItems) { if (item && item.type === 'menu' && item.menu) { const action = findInMenu(item.menu, event.nativeEvent.menuId); -@@ -63,6 +88,15 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref +@@ -68,6 +93,15 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref action.onPress(); return; } @@ -1497,7 +1499,7 @@ index 68e3ba6a78314aba908d07098bb6982d11e6ee80..db5d17bfdac19ed3e664b55b6a73ce49 } } } : undefined; -@@ -70,6 +104,8 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref +@@ -75,6 +109,8 @@ export const ScreenStackHeaderConfig = /*#__PURE__*/React.forwardRef((props, ref userInterfaceStyle: props.experimental_userInterfaceStyle, headerLeftBarButtonItems: preparedHeaderLeftBarButtonItems, headerRightBarButtonItems: preparedHeaderRightBarButtonItems, @@ -1507,17 +1509,19 @@ index 68e3ba6a78314aba908d07098bb6982d11e6ee80..db5d17bfdac19ed3e664b55b6a73ce49 onPressHeaderBarButtonMenuItem: onPressHeaderBarButtonMenuItem, ref: ref, diff --git a/lib/module/components/helpers/prepareHeaderBarButtonItems.js b/lib/module/components/helpers/prepareHeaderBarButtonItems.js -index 8a70ffd78617147418d628c03c580bb7ff9a8a72..bca930372d2a7c3f8e0a35c3dcf28474f899f21c 100644 +index 24bf271..693cfad 100644 --- a/lib/module/components/helpers/prepareHeaderBarButtonItems.js +++ b/lib/module/components/helpers/prepareHeaderBarButtonItems.js -@@ -1,5 +1,5 @@ - import { Image, processColor } from 'react-native'; +@@ -3,7 +3,7 @@ import { Image, processColor } from 'react-native'; + // Local nominal type so declaration emit doesn't resolve the RN alias down to + // the non-public `types_generated/.../AssetSourceResolver#ResolvedAssetSource`. + -const prepareMenu = (menu, index, side, path = '') => { +const prepareMenu = (menu, index, placement, path = '') => { return { ...menu, items: menu.items.map((menuItem, menuIndex) => { -@@ -20,7 +20,7 @@ const prepareMenu = (menu, index, side, path = '') => { +@@ -24,7 +24,7 @@ const prepareMenu = (menu, index, side, path = '') => { xcassetName, imageSource, templateSource, @@ -1526,7 +1530,7 @@ index 8a70ffd78617147418d628c03c580bb7ff9a8a72..bca930372d2a7c3f8e0a35c3dcf28474 }; } return { -@@ -29,16 +29,40 @@ const prepareMenu = (menu, index, side, path = '') => { +@@ -33,16 +33,40 @@ const prepareMenu = (menu, index, side, path = '') => { xcassetName, imageSource, templateSource, @@ -1570,7 +1574,7 @@ index 8a70ffd78617147418d628c03c580bb7ff9a8a72..bca930372d2a7c3f8e0a35c3dcf28474 let imageSource, templateSource; if (item.icon?.type === 'imageSource') { imageSource = Image.resolveAssetSource(item.icon.imageSource); -@@ -71,16 +95,16 @@ export const prepareHeaderBarButtonItems = (barButtonItems, side) => { +@@ -75,16 +99,16 @@ export const prepareHeaderBarButtonItems = (barButtonItems, side) => { if (item.type === 'button') { return { ...processedItem, @@ -1592,17 +1596,19 @@ index 8a70ffd78617147418d628c03c580bb7ff9a8a72..bca930372d2a7c3f8e0a35c3dcf28474 //# sourceMappingURL=prepareHeaderBarButtonItems.js.map \ No newline at end of file diff --git a/lib/typescript/components/helpers/prepareHeaderBarButtonItems.d.ts b/lib/typescript/components/helpers/prepareHeaderBarButtonItems.d.ts -index c41ef943e554754f599f2fcd157dd0dc61d78b7e..ed02d44f78ee3f1387ba93bf292be2b99bb0e3b3 100644 +index 4704a14..e2e2b78 100644 --- a/lib/typescript/components/helpers/prepareHeaderBarButtonItems.d.ts +++ b/lib/typescript/components/helpers/prepareHeaderBarButtonItems.d.ts -@@ -1,5 +1,5 @@ - import { HeaderBarButtonItem } from 'react-native-screens/types'; --export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButtonItem[], side: "left" | "right") => (import("react-native-screens/types").HeaderBarButtonItemSpacing | { -+export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButtonItem[], side: "left" | "right" | "center" | "toolbar") => (import("react-native-screens/types").HeaderBarButtonItemSpacing | { +@@ -2,7 +2,7 @@ import type { ImageResolvedAssetSource } from 'react-native'; + import type { HeaderBarButtonItem } from '../../types'; + export interface ResolvedImageAsset extends ImageResolvedAssetSource { + } +-export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButtonItem[], side: "left" | "right") => (import("../..").HeaderBarButtonItemSpacing | { ++export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButtonItem[], side: "left" | "right" | "center" | "toolbar") => (import("../..").HeaderBarButtonItemSpacing | { buttonId: string; - imageSource: import("react-native").ImageResolvedAssetSource | undefined; - templateSource: import("react-native").ImageResolvedAssetSource | undefined; -@@ -161,5 +161,5 @@ export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButt + imageSource: ResolvedImageAsset | undefined; + templateSource: ResolvedImageAsset | undefined; +@@ -164,5 +164,5 @@ export declare const prepareHeaderBarButtonItems: (barButtonItems: HeaderBarButt identifier?: string | undefined; accessibilityLabel?: string | undefined; accessibilityHint?: string | undefined; @@ -1611,7 +1617,7 @@ index c41ef943e554754f599f2fcd157dd0dc61d78b7e..ed02d44f78ee3f1387ba93bf292be2b9 //# sourceMappingURL=prepareHeaderBarButtonItems.d.ts.map \ No newline at end of file diff --git a/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts b/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts -index a51d8648567cff29cd2be0d5262bd15c6fc69c61..8b7439aff4d7e6fe8a72bf0bac93c3c19568b1a6 100644 +index ec39792..434bccf 100644 --- a/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts +++ b/lib/typescript/fabric/ScreenStackHeaderConfigNativeComponent.d.ts @@ -9,6 +9,7 @@ type OnPressHeaderBarButtonMenuItemEvent = Readonly<{ @@ -1647,7 +1653,7 @@ index a51d8648567cff29cd2be0d5262bd15c6fc69c61..8b7439aff4d7e6fe8a72bf0bac93c3c1 onPressHeaderBarButtonMenuItem?: CT.DirectEventHandler | undefined; synchronousShadowStateUpdatesEnabled?: CT.WithDefault; diff --git a/lib/typescript/fabric/ScreenStackHeaderSubviewNativeComponent.d.ts b/lib/typescript/fabric/ScreenStackHeaderSubviewNativeComponent.d.ts -index 1ca926e6753294861f5f79ab6267dc7999f70639..94e676fdb08ff9d1cf81a1cf06a45e931b5461f1 100644 +index 2cb1a79..d6ca5a4 100644 --- a/lib/typescript/fabric/ScreenStackHeaderSubviewNativeComponent.d.ts +++ b/lib/typescript/fabric/ScreenStackHeaderSubviewNativeComponent.d.ts @@ -3,6 +3,7 @@ export type HeaderSubviewTypes = 'back' | 'right' | 'left' | 'title' | 'center' @@ -1657,12 +1663,12 @@ index 1ca926e6753294861f5f79ab6267dc7999f70639..94e676fdb08ff9d1cf81a1cf06a45e93 + identifier?: string | undefined; synchronousShadowStateUpdatesEnabled?: CT.WithDefault; } - declare const _default: import("react-native").HostComponent; + declare const _default: HostComponent; diff --git a/lib/typescript/types.d.ts b/lib/typescript/types.d.ts -index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90b91d826a 100644 +index ff37881..b487303 100644 --- a/lib/typescript/types.d.ts +++ b/lib/typescript/types.d.ts -@@ -10,6 +10,7 @@ export type SearchBarCommands = { +@@ -19,6 +19,7 @@ export type SearchBarCommands = { cancelSearch: () => void; }; export type BackButtonDisplayMode = 'default' | 'generic' | 'minimal'; @@ -1670,7 +1676,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 export type StackPresentationTypes = 'push' | 'modal' | 'transparentModal' | 'containedModal' | 'containedTransparentModal' | 'fullScreenModal' | 'formSheet' | 'pageSheet'; export type StackAnimationTypes = 'default' | 'fade' | 'fade_from_bottom' | 'flip' | 'none' | 'simple_push' | 'slide_from_bottom' | 'slide_from_right' | 'slide_from_left' | 'ios_from_right' | 'ios_from_left'; export type BlurEffectTypes = BlurEffect; -@@ -631,6 +632,14 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -650,6 +651,14 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * @platform ios */ backButtonDisplayMode?: BackButtonDisplayMode | undefined; @@ -1685,7 +1691,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 /** * Array of UIBarButtomItems to the left side of the header. * -@@ -643,6 +652,26 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -662,6 +671,26 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * @platform ios */ headerRightBarButtonItems?: HeaderBarButtonItem[] | undefined; @@ -1712,7 +1718,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 /** * When set to true the header will be hidden while the parent Screen is on the top of the stack. The default value is false. */ -@@ -704,6 +733,20 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -723,6 +752,20 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * String that can be displayed in the header as a fallback for `headerTitle`. */ title?: string | undefined; @@ -1733,7 +1739,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 /** * Allows for setting text color of the title. */ -@@ -999,6 +1042,13 @@ export interface SearchBarProps { +@@ -1018,6 +1061,13 @@ export interface SearchBarProps { shouldShowHintSearchIcon?: boolean | undefined; } export interface ScreenStackHeaderSubviewProps { @@ -1747,7 +1753,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 /** * A boolean value indicating whether the background this item may share with other items in the bar should be hidden. * Only applicable to type="right" and type="left" subviews. -@@ -1037,6 +1087,11 @@ interface SharedHeaderBarButtonItem { +@@ -1056,6 +1106,11 @@ interface SharedHeaderBarButtonItem { * Read more: https://developer.apple.com/documentation/uikit/uibarbuttonitem/style-swift.property */ variant?: 'plain' | 'done' | 'prominent' | undefined; @@ -1759,7 +1765,7 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 /** * The tint color to apply to the item. * -@@ -1181,8 +1236,38 @@ export interface HeaderBarButtonItemWithMenu extends SharedHeaderBarButtonItem { +@@ -1201,8 +1256,38 @@ export interface HeaderBarButtonItemWithMenu extends SharedHeaderBarButtonItem { export interface HeaderBarButtonItemSpacing { type: 'spacing'; spacing: number; @@ -1800,10 +1806,10 @@ index 10a31341f4eff258a7f8ea6abae3eddf0dd21218..bab5031f5f9b246f15e5396f3f2fee90 * Custom Screen Transition */ diff --git a/src/components/ScreenStackHeaderConfig.tsx b/src/components/ScreenStackHeaderConfig.tsx -index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e87640767 100644 +index 509d6cd..761e49b 100644 --- a/src/components/ScreenStackHeaderConfig.tsx +++ b/src/components/ScreenStackHeaderConfig.tsx -@@ -48,7 +48,12 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -54,7 +54,12 @@ export const ScreenStackHeaderConfig = React.forwardRef< props.disableBottomInsetApplication ?? false, ); @@ -1817,7 +1823,7 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e const preparedHeaderLeftBarButtonItems = headerLeftBarButtonItems && isHeaderBarButtonsAvailableForCurrentPlatform -@@ -58,22 +63,36 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -64,22 +69,36 @@ export const ScreenStackHeaderConfig = React.forwardRef< headerRightBarButtonItems && isHeaderBarButtonsAvailableForCurrentPlatform ? prepareHeaderBarButtonItems(headerRightBarButtonItems, 'right') : undefined; @@ -1858,7 +1864,7 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e ); if ( pressedItem && -@@ -81,6 +100,32 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -87,6 +106,32 @@ export const ScreenStackHeaderConfig = React.forwardRef< pressedItem.onPress ) { pressedItem.onPress(); @@ -1891,7 +1897,7 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e } } : undefined; -@@ -111,6 +156,8 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -117,6 +162,8 @@ export const ScreenStackHeaderConfig = React.forwardRef< const allItems = [ ...(preparedHeaderLeftBarButtonItems ?? []), ...(preparedHeaderRightBarButtonItems ?? []), @@ -1900,7 +1906,7 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e ]; for (const item of allItems) { if (item && item.type === 'menu' && item.menu) { -@@ -119,6 +166,17 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -125,6 +172,17 @@ export const ScreenStackHeaderConfig = React.forwardRef< action.onPress(); return; } @@ -1918,7 +1924,7 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e } } } -@@ -130,6 +188,8 @@ export const ScreenStackHeaderConfig = React.forwardRef< +@@ -136,6 +194,8 @@ export const ScreenStackHeaderConfig = React.forwardRef< userInterfaceStyle={props.experimental_userInterfaceStyle} headerLeftBarButtonItems={preparedHeaderLeftBarButtonItems} headerRightBarButtonItems={preparedHeaderRightBarButtonItems} @@ -1928,10 +1934,10 @@ index c3a88b6f6c8362cf717372a35cdc35a6b397bdd0..9e8173da567933fd3f6819fb26bf4a0e onPressHeaderBarButtonMenuItem={onPressHeaderBarButtonMenuItem} ref={ref} diff --git a/src/components/helpers/prepareHeaderBarButtonItems.ts b/src/components/helpers/prepareHeaderBarButtonItems.ts -index be2c24dfee77f5883b5ab1d7473be80933b5dc6f..2008a342f13806641909c19a9f4ab6829f239016 100644 +index 19ab7bc..9fd5ceb 100644 --- a/src/components/helpers/prepareHeaderBarButtonItems.ts +++ b/src/components/helpers/prepareHeaderBarButtonItems.ts -@@ -7,7 +7,7 @@ import { +@@ -12,7 +12,7 @@ export interface ResolvedImageAsset extends ImageResolvedAssetSource {} const prepareMenu = ( menu: HeaderBarButtonItemWithMenu['menu'], index: number, @@ -1940,7 +1946,7 @@ index be2c24dfee77f5883b5ab1d7473be80933b5dc6f..2008a342f13806641909c19a9f4ab682 path: string = '', ): HeaderBarButtonItemWithMenu['menu'] => { return { -@@ -34,7 +34,7 @@ const prepareMenu = ( +@@ -39,7 +39,7 @@ const prepareMenu = ( xcassetName, imageSource, templateSource, @@ -1949,7 +1955,7 @@ index be2c24dfee77f5883b5ab1d7473be80933b5dc6f..2008a342f13806641909c19a9f4ab682 }; } return { -@@ -43,20 +43,53 @@ const prepareMenu = ( +@@ -48,20 +48,53 @@ const prepareMenu = ( xcassetName, imageSource, templateSource, @@ -2004,10 +2010,10 @@ index be2c24dfee77f5883b5ab1d7473be80933b5dc6f..2008a342f13806641909c19a9f4ab682 + composeMenu: item.composeMenu ? prepareMenu(item.composeMenu, index, placement, 'compose') : undefined, + }; + } - let imageSource, templateSource; + let imageSource: ResolvedImageAsset | undefined, + templateSource: ResolvedImageAsset | undefined; if (item.icon?.type === 'imageSource') { - imageSource = Image.resolveAssetSource(item.icon.imageSource); -@@ -91,15 +124,15 @@ export const prepareHeaderBarButtonItems = ( +@@ -97,15 +130,15 @@ export const prepareHeaderBarButtonItems = ( if (item.type === 'button') { return { ...processedItem, @@ -2027,10 +2033,10 @@ index be2c24dfee77f5883b5ab1d7473be80933b5dc6f..2008a342f13806641909c19a9f4ab682 + }).filter(item => item !== null); }; diff --git a/src/fabric/ScreenStackHeaderConfigNativeComponent.ts b/src/fabric/ScreenStackHeaderConfigNativeComponent.ts -index a80d9fef0c0ab5ce8221c5e0c7fae65162bc6164..fc16f51425702a418c09de553a54753331f19d15 100644 +index da28c51..1136622 100644 --- a/src/fabric/ScreenStackHeaderConfigNativeComponent.ts +++ b/src/fabric/ScreenStackHeaderConfigNativeComponent.ts -@@ -14,6 +14,7 @@ type OnPressHeaderBarButtonItemEvent = Readonly<{ buttonId: string }>; +@@ -19,6 +19,7 @@ type OnPressHeaderBarButtonItemEvent = Readonly<{ buttonId: string }>; type OnPressHeaderBarButtonMenuItemEvent = Readonly<{ menuId: string }>; type BackButtonDisplayMode = 'minimal' | 'default' | 'generic'; @@ -2038,7 +2044,7 @@ index a80d9fef0c0ab5ce8221c5e0c7fae65162bc6164..fc16f51425702a418c09de553a547533 type BlurEffect = | 'none' -@@ -61,12 +62,15 @@ export interface NativeProps extends ViewProps { +@@ -66,12 +67,15 @@ export interface NativeProps extends ViewProps { largeTitleColor?: ColorValue | undefined; translucent?: boolean | undefined; title?: string | undefined; @@ -2054,7 +2060,7 @@ index a80d9fef0c0ab5ce8221c5e0c7fae65162bc6164..fc16f51425702a418c09de553a547533 hideBackButton?: boolean | undefined; backButtonInCustomView?: boolean | undefined; blurEffect?: CT.WithDefault; -@@ -74,6 +78,8 @@ export interface NativeProps extends ViewProps { +@@ -79,6 +83,8 @@ export interface NativeProps extends ViewProps { topInsetEnabled?: boolean | undefined; headerLeftBarButtonItems?: CT.UnsafeMixed[] | undefined; headerRightBarButtonItems?: CT.UnsafeMixed[] | undefined; @@ -2064,10 +2070,10 @@ index a80d9fef0c0ab5ce8221c5e0c7fae65162bc6164..fc16f51425702a418c09de553a547533 | CT.DirectEventHandler | undefined; diff --git a/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts b/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts -index 7d3fbfe08c70461936832a40a1ce8d9c11b22457..1f9caca6271b68d182b70a180f180d6a4ce3988c 100644 +index 9a6af57..03aa2b2 100644 --- a/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts +++ b/src/fabric/ScreenStackHeaderSubviewNativeComponent.ts -@@ -14,6 +14,7 @@ export type HeaderSubviewTypes = +@@ -18,6 +18,7 @@ export type HeaderSubviewTypes = export interface NativeProps extends ViewProps { type?: CT.WithDefault; hidesSharedBackground?: boolean | undefined; @@ -2076,10 +2082,10 @@ index 7d3fbfe08c70461936832a40a1ce8d9c11b22457..1f9caca6271b68d182b70a180f180d6a } diff --git a/src/types.tsx b/src/types.tsx -index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47caf2466d 100644 +index 8594b73..20c6e88 100644 --- a/src/types.tsx +++ b/src/types.tsx -@@ -26,6 +26,7 @@ export type SearchBarCommands = { +@@ -35,6 +35,7 @@ export type SearchBarCommands = { }; export type BackButtonDisplayMode = 'default' | 'generic' | 'minimal'; @@ -2087,7 +2093,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 export type StackPresentationTypes = | 'push' | 'modal' -@@ -735,6 +736,14 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -754,6 +755,14 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * @platform ios */ backButtonDisplayMode?: BackButtonDisplayMode | undefined; @@ -2102,7 +2108,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 /** * Array of UIBarButtomItems to the left side of the header. * -@@ -747,6 +756,26 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -766,6 +775,26 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * @platform ios */ headerRightBarButtonItems?: HeaderBarButtonItem[] | undefined; @@ -2129,7 +2135,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 /** * When set to true the header will be hidden while the parent Screen is on the top of the stack. The default value is false. */ -@@ -808,6 +837,20 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { +@@ -827,6 +856,20 @@ export interface ScreenStackHeaderConfigProps extends ViewProps { * String that can be displayed in the header as a fallback for `headerTitle`. */ title?: string | undefined; @@ -2150,7 +2156,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 /** * Allows for setting text color of the title. */ -@@ -1120,6 +1163,13 @@ export interface SearchBarProps { +@@ -1139,6 +1182,13 @@ export interface SearchBarProps { } export interface ScreenStackHeaderSubviewProps { @@ -2164,7 +2170,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 /** * A boolean value indicating whether the background this item may share with other items in the bar should be hidden. * Only applicable to type="right" and type="left" subviews. -@@ -1161,6 +1211,11 @@ interface SharedHeaderBarButtonItem { +@@ -1180,6 +1230,11 @@ interface SharedHeaderBarButtonItem { * Read more: https://developer.apple.com/documentation/uikit/uibarbuttonitem/style-swift.property */ variant?: 'plain' | 'done' | 'prominent' | undefined; @@ -2176,7 +2182,7 @@ index 9c3ab4c3653ee1769addda8a6464cdf49695a601..6f242ad2bbd7152ea9f873ef7754ad47 /** * The tint color to apply to the item. * -@@ -1315,11 +1370,47 @@ export interface HeaderBarButtonItemWithMenu extends SharedHeaderBarButtonItem { +@@ -1335,11 +1390,47 @@ export interface HeaderBarButtonItemWithMenu extends SharedHeaderBarButtonItem { export interface HeaderBarButtonItemSpacing { type: 'spacing'; spacing: number; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6ef065c7af83..5da642b3b618 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -69,52 +69,50 @@ overrides: '@effect/sql-pg': 4.0.0-rc.115 '@effect/vitest': 4.0.0-rc.115 '@effect/vitest>vitest': '-' - '@expo/dom-webview': 57.0.1 - '@expo/metro-config': 57.0.12 - expo-constants: 57.0.16 - expo-modules-core: 57.0.14 + '@expo/dom-webview': 58.0.2 + '@expo/metro-config': 58.0.6 + expo-constants: 58.0.9 + expo-router: 58.0.10 + expo-sharing>@expo/config-plugins: 58.0.4 + expo-sharing>@expo/config-types: 58.0.2 '@pierre/diffs>@shikijs/transformers': ^4.2.0 '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 '@tailwindcss/vite': 4.3.3 '@types/node': 24.12.4 effect: 4.0.0-rc.115 - expo-router: 57.0.17 - expo-sharing>@expo/config-plugins: 57.0.9 - expo-sharing>@expo/config-types: 57.0.2 node-abi: 4.33.0 lightningcss: 1.33.0 tailwindcss: 4.3.3 vite: npm:@voidzero-dev/vite-plus-core@1.0.0 yaml: ^2.9.0 -packageExtensionsChecksum: sha256-k/dT9NFDl5hihRPaoFKeY11hzyutMFs5psfZLFiKJic= +packageExtensionsChecksum: sha256-34mvKz5PLlrn2Tt9jUJC1SbK5hRE+oxwqyC1J6r09oE= patchedDependencies: - '@clerk/expo@4.6.8': a82bb41039ee88a290a87d4ab58be7be4c49fa338603b17ea646e1ec140a1cfb + '@clerk/expo@4.6.8': b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281 '@effect/vitest@4.0.0-rc.115': 172bd95ef73a13d322888984415d5d18d9d2aa8e13fa529eac235efac837e902 - '@expo/metro-config@57.0.12': 96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2 + '@expo/metro-config@58.0.6': 90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760 '@ff-labs/fff-node@0.9.4': c4e3cc2420ceb9dc650f9d189e9c24baf7e83f342998bacda5f459a4ce7927a8 '@legendapp/list@3.3.5': 680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806 '@pierre/diffs@1.3.0-beta.10': 0ccee155b93b63d810e2c1a40c1fd676fb6fbcfa72cf6430dcedf1a3ae475ab4 '@react-native-ai/apple@0.12.0': 2d09870c2848d185cb05b53ed823a46e12dba519324d8dd8e584e28731990f9d - '@react-native-menu/menu@2.0.0': f63d256bf6a97a873b5e628eb595bd6ef0075ddd5bdd890fc920f7a6024290dd + '@react-native-menu/menu@2.0.0': 1cc2d43fbd0281ca0dd1feb5ffcefee7d4419459c8daaa58effff10c657832fb '@react-navigation/native-stack@7.17.6': e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552 alchemy@2.0.0-beta.79: d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8 dbus-next@0.10.2: cfff57561b0ee59b5addb3b2e6c6f20906e967507a530ab67e8db8108e520ba4 effect@4.0.0-rc.115: 0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5 - expo-audio@57.0.4: fa9a3e0442ed395d4071bb406e08c3a471c9a84700bdfa0b9ad7ff144c96041a - expo-modules-core@57.0.14: 6be7092f8c6f03a57b75c797d98b5f19ed62d2dd205bfc4c8adf4cef45655d7e - expo-notifications@57.0.15: f89252c2c08dc7b3acb8415f319ebbe15fff8c9f88a64ebe1830cd5ac5c9ac40 - expo-sharing@57.0.17: 8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45 - expo-widgets@57.0.15: 319a9ded5db49c5b5215c511a138b33f44c7ea2972eb418192e8d5342fe75ce6 + expo-audio@58.0.3: c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742 + expo-blur@58.0.2: d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18 + expo-glass-effect@58.0.3: f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57 + expo-sharing@58.0.12: 5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8 + expo-widgets@58.0.9: 94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b node-pty@1.2.0-beta.15: f2fe901c61cde17986240002d05c172d5d0272d83ffaab8d0ebeb922763be414 - react-native-gesture-handler@2.32.0: 0579f8e4dad02bf3183d95b02620358412983c36f9bda7425dc8bcb9643b5ce2 - react-native-keyboard-controller@1.21.13: 6e4339347bc5bb3c9ea67d85ff5c814058b211c5750f247aba59d07869a2e787 + react-native-gesture-handler@3.2.1: d518a937e3cb2df5e7d67f1ab6b265c74a8639e4572d1b032b7b747e9b1c01a9 + react-native-keyboard-controller@1.22.4: a438114039aed2e280a81d95c25723132ad071e4768fe492bd92aa628ad74597 react-native-nitro-markdown@0.5.8: 642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c - react-native-nitro-modules@0.35.9: 825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675 - react-native-reanimated@4.5.5: bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d - react-native-screens@4.26.2: 595114f3f9ce8b9f0d99d1aafe5c12c997b7d75ca9add31d46cbedbfe347b8e0 + react-native-nitro-modules@0.35.9: daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2 + react-native-screens@4.28.0: cc1301436ee62c39860acc9ee1a1e60b7d47e6abd211c42effa62c056d165483 uniwind@1.11.0: a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625 importers: @@ -144,7 +142,7 @@ importers: dependencies: '@clerk/electron': specifier: 0.0.44 - version: 0.0.44(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@44.4.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 0.0.44(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@44.4.2)(react-dom@19.3.0(react@19.3.0))(react@19.2.6) '@clerk/electron-passkeys': specifier: 0.0.3 version: 0.0.3 @@ -245,19 +243,22 @@ importers: dependencies: '@clerk/expo': specifier: 4.6.8 - version: 4.6.8(patch_hash=a82bb41039ee88a290a87d4ab58be7be4c49fa338603b17ea646e1ec140a1cfb)(dbc31631339ce74330e188d5d7a88158) + version: 4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(950bb7335d61b76ffb649f136fc0d4df) '@effect/atom-react': specifier: 4.0.0-rc.115 - version: 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.2.3)(scheduler@0.27.0) + version: 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.3.0)(scheduler@0.27.0) '@expo-google-fonts/dm-sans': specifier: ^0.4.2 version: 0.4.2 + '@expo/metro-runtime': + specifier: ~58.0.9 + version: 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/ui': - specifier: ~57.0.14 - version: 57.0.14(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.9 + version: 58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@legendapp/list': specifier: 'catalog:' - version: 3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@material/material-color-utilities': specifier: 0.3.0 version: 0.3.0 @@ -266,22 +267,22 @@ importers: version: 1.9.1 '@pierre/diffs': specifier: 'catalog:' - version: 1.3.0-beta.10(patch_hash=0ccee155b93b63d810e2c1a40c1fd676fb6fbcfa72cf6430dcedf1a3ae475ab4)(@shikijs/themes@4.2.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.3.0-beta.10(patch_hash=0ccee155b93b63d810e2c1a40c1fd676fb6fbcfa72cf6430dcedf1a3ae475ab4)(@shikijs/themes@4.2.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@react-native-ai/apple': specifier: 0.12.0 - version: 0.12.0(patch_hash=2d09870c2848d185cb05b53ed823a46e12dba519324d8dd8e584e28731990f9d)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + version: 0.12.0(patch_hash=2d09870c2848d185cb05b53ed823a46e12dba519324d8dd8e584e28731990f9d)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) '@react-native-menu/menu': specifier: ^2.0.0 - version: 2.0.0(patch_hash=f63d256bf6a97a873b5e628eb595bd6ef0075ddd5bdd890fc920f7a6024290dd)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 2.0.0(patch_hash=1cc2d43fbd0281ca0dd1feb5ffcefee7d4419459c8daaa58effff10c657832fb)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@react-navigation/elements': specifier: 2.9.26 - version: 2.9.26(c10301b6e0c42fc6434d2b643197a81e) + version: 2.9.26(83de68753219ecf7f3321e065bd378be) '@react-navigation/native': specifier: 7.3.4 - version: 7.3.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@react-navigation/native-stack': specifier: 7.17.6 - version: 7.17.6(patch_hash=e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552)(f640afa6cd4b9a1dc5422cbafdc82f53) + version: 7.17.6(patch_hash=e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552)(cdeee8948497d4b80ffe015e2a003650) '@shikijs/core': specifier: 4.2.0 version: 4.2.0 @@ -302,7 +303,7 @@ importers: version: link:../../packages/contracts '@t3tools/mobile-markdown-text': specifier: file:./modules/t3-markdown-text - version: file:apps/mobile/modules/t3-markdown-text(c883758f8793b29a89016166016b354e) + version: file:apps/mobile/modules/t3-markdown-text(5c46709ff7a3b3b481fcdaa30ae2beb2) '@t3tools/mobile-review-diff-native': specifier: file:./modules/t3-review-diff version: file:apps/mobile/modules/t3-review-diff @@ -314,7 +315,7 @@ importers: version: link:../../packages/shared '@tabler/icons-react-native': specifier: ^3.44.0 - version: 3.44.0(react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react@19.2.3) + version: 3.44.0(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react@19.3.0) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -325,155 +326,155 @@ importers: specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) expo: - specifier: ~57.0.18 - version: 57.0.18(41fd11498a34454c91128cdad32f22f8) + specifier: 58.0.0 + version: 58.0.0(3abfa3879936d948a635873738556226) expo-asset: - specifier: ~57.0.15 - version: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-audio: - specifier: 57.0.4 - version: 57.0.4(patch_hash=fa9a3e0442ed395d4071bb406e08c3a471c9a84700bdfa0b9ad7ff144c96041a)(expo-asset@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 58.0.3 + version: 58.0.3(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-auth-session: - specifier: ~57.0.10 - version: 57.0.10(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.6 + version: 58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-blur: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 58.0.2 + version: 58.0.2(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-build-properties: - specifier: ~57.0.15 - version: 57.0.15(expo@57.0.18) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0) expo-camera: - specifier: ~57.0.4 - version: 57.0.4(@types/emscripten@1.41.5)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.5 + version: 58.0.5(@types/emscripten@1.41.5)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-clipboard: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.2 + version: 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-constants: - specifier: 57.0.16 - version: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + specifier: 58.0.9 + version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) expo-crypto: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.0) expo-dev-client: - specifier: ~57.0.16 - version: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-device: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.18) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.0) expo-document-picker: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.18) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.0) expo-file-system: - specifier: ~57.0.6 - version: 57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-font: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-glass-effect: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 58.0.3 + version: 58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-haptics: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.0) expo-image: - specifier: ~57.0.3 - version: 57.0.3(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.8 + version: 58.0.8(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-image-manipulator: - specifier: ~57.0.17 - version: 57.0.17(expo@57.0.18) + specifier: ~58.0.10 + version: 58.0.10(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-image-picker: - specifier: ~57.0.14 - version: 57.0.14(expo@57.0.18) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0) expo-keep-awake: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18)(react@19.2.3) + specifier: ~58.0.2 + version: 58.0.2(expo@58.0.0)(react@19.3.0) expo-linking: - specifier: ~57.0.8 - version: 57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-network: - specifier: ~57.0.1 - version: 57.0.1(expo@57.0.18)(react@19.2.3) + specifier: ~58.0.2 + version: 58.0.2(expo@58.0.0)(react@19.3.0) expo-notifications: - specifier: 57.0.15 - version: 57.0.15(patch_hash=f89252c2c08dc7b3acb8415f319ebbe15fff8c9f88a64ebe1830cd5ac5c9ac40)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) + specifier: ~58.0.9 + version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-paste-input: specifier: ^0.1.15 - version: 0.1.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 0.1.15(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-quick-actions: specifier: ^6.0.2 - version: 6.0.2(expo@57.0.18)(typescript@7.0.2) + version: 6.0.2(expo@58.0.0)(typescript@7.0.2) expo-secure-store: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18) + specifier: ~58.0.1 + version: 58.0.1(expo@58.0.0) expo-sharing: - specifier: 57.0.17 - version: 57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) + specifier: 58.0.12 + version: 58.0.12(patch_hash=5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-splash-screen: - specifier: ~57.0.8 - version: 57.0.8(expo@57.0.18)(typescript@7.0.2) + specifier: ~58.0.2 + version: 58.0.2(expo@58.0.0)(typescript@7.0.2) expo-sqlite: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.7 + version: 58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-symbols: - specifier: ~57.0.2 - version: 57.0.2(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.3 + version: 58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-updates: - specifier: ~57.0.19 - version: 57.0.19(expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.11 + version: 58.0.11(expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-video: - specifier: ~57.0.3 - version: 57.0.3(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~58.0.5 + version: 58.0.5(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-web-browser: - specifier: ~57.0.2 - version: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-widgets: - specifier: 57.0.15 - version: 57.0.15(patch_hash=319a9ded5db49c5b5215c511a138b33f44c7ea2972eb418192e8d5342fe75ce6)(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 58.0.9 + version: 58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react: - specifier: 19.2.3 - version: 19.2.3 + specifier: 19.3.0 + version: 19.3.0 react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) + specifier: 19.3.0 + version: 19.3.0(react@19.3.0) react-native: - specifier: 0.86.3 - version: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + specifier: 0.88.0-rc.3 + version: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) react-native-gesture-handler: - specifier: ~2.32.0 - version: 2.32.0(patch_hash=0579f8e4dad02bf3183d95b02620358412983c36f9bda7425dc8bcb9643b5ce2)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~3.2.1 + version: 3.2.1(patch_hash=d518a937e3cb2df5e7d67f1ab6b265c74a8639e4572d1b032b7b747e9b1c01a9)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-image-viewing: specifier: ^0.2.2 - version: 0.2.2(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 0.2.2(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-keyboard-controller: - specifier: 1.21.13 - version: 1.21.13(patch_hash=6e4339347bc5bb3c9ea67d85ff5c814058b211c5750f247aba59d07869a2e787)(react-native-reanimated@4.5.5(patch_hash=bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 1.22.4 + version: 1.22.4(patch_hash=a438114039aed2e280a81d95c25723132ad071e4768fe492bd92aa628ad74597)(react-native-reanimated@4.7.0(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-nitro-markdown: specifier: ^0.5.0 - version: 0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-nitro-modules: specifier: 0.35.9 - version: 0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-reanimated: - specifier: 4.5.5 - version: 4.5.5(patch_hash=bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 4.7.0 + version: 4.7.0(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-safe-area-context: - specifier: ~5.7.0 - version: 5.7.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~5.9.1 + version: 5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-screens: - specifier: ~4.26.0 - version: 4.26.2(patch_hash=595114f3f9ce8b9f0d99d1aafe5c12c997b7d75ca9add31d46cbedbfe347b8e0)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: ~4.28.0 + version: 4.28.0(patch_hash=cc1301436ee62c39860acc9ee1a1e60b7d47e6abd211c42effa62c056d165483)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-shiki-engine: specifier: ^0.3.12 - version: 0.3.12(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + version: 0.3.12(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-svg: - specifier: 15.15.4 - version: 15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 15.15.5 + version: 15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-webview: - specifier: ^13.16.1 - version: 13.16.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 14.0.1 + version: 14.0.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-native-worklets: - specifier: 0.11.4 - version: 0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + specifier: 0.13.0 + version: 0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) shiki: specifier: 4.2.0 version: 4.2.0 @@ -482,23 +483,23 @@ importers: version: 3.6.0 uniwind: specifier: 1.11.0 - version: 1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.84.5)(metro-transform-worker@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(tailwindcss@4.3.3) + version: 1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3) devDependencies: '@effect/vitest': specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(patch_hash=172bd95ef73a13d322888984415d5d18d9d2aa8e13fa529eac235efac837e902)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) '@pierre/trees': specifier: 1.0.0-beta.4 - version: 1.0.0-beta.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.0.0-beta.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@types/react': - specifier: ~19.2.0 - version: 19.2.16 + specifier: ~19.3.0 + version: 19.3.0 '@types/react-dom': specifier: ~19.2.3 - version: 19.2.3(@types/react@19.2.16) + version: 19.2.3(@types/react@19.3.0) babel-preset-expo: - specifier: ~57.0.9 - version: 57.0.9(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@57.0.15)(expo@57.0.18)(react-refresh@0.14.2) + specifier: ~58.0.6 + version: 58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2) tailwindcss: specifier: 4.3.3 version: 4.3.3 @@ -595,7 +596,7 @@ importers: dependencies: '@base-ui/react': specifier: ^1.4.1 - version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.16)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.3.0)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@clerk/electron': specifier: 0.0.44 version: 0.0.44(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@44.4.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -604,7 +605,7 @@ importers: version: 6.16.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@daypicker/react': specifier: ^10.0.1 - version: 10.0.1(@types/react@19.2.16)(react@19.2.6) + version: 10.0.1(@types/react@19.3.0)(react@19.2.6) '@dnd-kit/core': specifier: ^6.3.1 version: 6.3.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -667,7 +668,7 @@ importers: version: 3.31.3 '@tiptap/react': specifier: ^3.31.3 - version: 3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tiptap/starter-kit': specifier: ^3.31.3 version: 3.31.3 @@ -709,7 +710,7 @@ importers: version: 19.2.6(react@19.2.6) react-markdown: specifier: ^10.1.0 - version: 10.1.0(@types/react@19.2.16)(react@19.2.6) + version: 10.1.0(@types/react@19.3.0)(react@19.2.6) rehype-raw: specifier: ^7.0.0 version: 7.0.0 @@ -727,7 +728,7 @@ importers: version: 3.6.0 zustand: specifier: ^5.0.11 - version: 5.0.14(@types/react@19.2.16)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) + version: 5.0.14(@types/react@19.3.0)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)) devDependencies: '@effect/platform-node': specifier: 4.0.0-rc.115 @@ -757,11 +758,11 @@ importers: specifier: ^4.0.4 version: 4.0.4 '@types/react': - specifier: ~19.2.14 - version: 19.2.16 + specifier: ~19.3.0 + version: 19.3.0 '@types/react-dom': specifier: ~19.2.3 - version: 19.2.3(@types/react@19.2.16) + version: 19.2.3(@types/react@19.3.0) '@types/react-test-renderer': specifier: 19.1.0 version: 19.1.0 @@ -800,7 +801,7 @@ importers: dependencies: '@clerk/backend': specifier: 3.18.1 - version: 3.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 3.18.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6) '@effect/sql-pg': specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) @@ -821,10 +822,10 @@ importers: version: link:../../packages/shared alchemy: specifier: 2.0.0-beta.79 - version: 2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.2.16)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(31bc26b129d6bba2f2e387113f50dba2))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + version: 2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) drizzle-orm: specifier: 1.0.0-rc.5-ab785fc - version: 1.0.0-rc.5-ab785fc(31bc26b129d6bba2f2e387113f50dba2) + version: 1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150) effect: specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) @@ -1096,6 +1097,15 @@ importers: packages: + 2g@0.4.4: + resolution: {integrity: sha512-ZwH02IRQicm+92YzJZMS8imSAJaqTPI+VASb1zMnisotnWcEP4e7nb57Mr8C2dGAA5G8ZmialbMmpkGLWgAY/w==} + hasBin: true + peerDependencies: + typescript: '>=5.8.0' + peerDependenciesMeta: + typescript: + optional: true + '@ai-sdk/provider-utils@4.0.49': resolution: {integrity: sha512-8e7pd+82bobqrFOaD5dG/PiEuvLYr5olaE3I56ch0jipR0H7sGD6ohwTUynv6k8O8QidWiyIbEsZCtr/2dyXIA==} engines: {node: '>=18.17'} @@ -1688,12 +1698,6 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.28.6': - resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx@7.29.7': resolution: {integrity: sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==} engines: {node: '>=6.9.0'} @@ -1921,7 +1925,7 @@ packages: expo: '>=54 <58' expo-apple-authentication: '>=7.0.0' expo-auth-session: '>=5' - expo-constants: 57.0.16 + expo-constants: 58.0.9 expo-crypto: '>=12' expo-local-authentication: '>=13.5.0' expo-secure-store: '>=12.4.0' @@ -2286,10 +2290,6 @@ packages: peerDependencies: effect: 4.0.0-rc.115 - '@egjs/hammerjs@2.0.17': - resolution: {integrity: sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==} - engines: {node: '>=0.8.0'} - '@electric-sql/pglite@0.3.15': resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==} @@ -2732,12 +2732,12 @@ packages: '@expo-google-fonts/material-symbols@0.4.38': resolution: {integrity: sha512-IJkBtN1o8u9BW5fvSii1MyHPQ7Q0HxbWcVBvOrOzgMLpVtZw7R2w94wBTVR7kZwv3w1JNTESMmLA5Sqn1+Z36A==} - '@expo/cli@57.0.20': - resolution: {integrity: sha512-ZjWz7SA5TBTyKq4+aFRUPgMFxmqHtKkDMv6d85J2UAAjdRhkNRf+B80t+rr5IFo2ywuTvyrPRBth4ei4w08olA==} + '@expo/cli@58.0.9': + resolution: {integrity: sha512-qoCjBSbq8sFmhPHA0jgDvkRdGvVm9Wjti0U/zlrqYrH/lVolqT8++RvWebCLIGrT1WHQ9HWOmaL7szKqbhVgiA==} hasBin: true peerDependencies: expo: '*' - expo-router: 57.0.17 + expo-router: 58.0.10 react-native: '*' peerDependenciesMeta: expo-router: @@ -2748,85 +2748,91 @@ packages: '@expo/code-signing-certificates@0.0.6': resolution: {integrity: sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w==} - '@expo/config-plugins@57.0.9': - resolution: {integrity: sha512-hHgfL1avkCdEvDSw7IwlKwRYYNgcxzbNNMIk6W6lTkJpY0MajinAfeJUS0J+wPCsjUfGbVqOJM+XhPaO5ulUxg==} + '@expo/config-plugins@58.0.4': + resolution: {integrity: sha512-JlZSHqYPU7nrU1E68KGpoW9pcXYgHfKOeTnqXXOop/4yj9UarOe9Y26Wlp6fhXjZ28ZooBJxo3J0Z5SSuLfbDQ==} - '@expo/config-types@57.0.2': - resolution: {integrity: sha512-ewW08OonrcRIsRKIlFvvcmmafE5zemb1ocu3HkNwtVPyRtj2w42pZCAkMIROYpcVBaPnc3mDT9UZDzwXWC3i6g==} + '@expo/config-types@58.0.2': + resolution: {integrity: sha512-iXoMw0/8KVSrrGRxOnf69eB9k5iPomOH7RPJnYEErAMFCfl2QCkftkHVSUdZ3qxtpx9EjRm0MANyAoQj77U7qw==} - '@expo/config@57.0.9': - resolution: {integrity: sha512-dmzlKraIFxa7wLwV6K7WzI8jp6QZpW6Mc5mGjLimJUFjzh4uQdYaT3m3plEutM5yxBoBEwqzks7l+I/ljCbxAQ==} + '@expo/config@58.0.1': + resolution: {integrity: sha512-sFI8mxS2p3E08xOGk1fKTQiuF27EQj1evwT4fXeMoaD6RjDJJDVmwJ27FMb6d4a/NObwgieIlGtoCE0+mmfD4A==} '@expo/devcert@1.2.1': resolution: {integrity: sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA==} - '@expo/devtools@57.0.1': - resolution: {integrity: sha512-GyUf+wFNkbttaX0jR7MZa9bm77U0IrLg6d2AjpxdyoXw/w4abHoXG0oFufwLMgP9zLTd5+Ct4X/ffNUTnlzZgg==} + '@expo/devtools@58.0.2': + resolution: {integrity: sha512-WBj/K+vv8JPSmY70ennL04YYOHkpEsGGkfuVY9lfv4XO7Qhbt5qz4q6W7maME194I5oGcimRMigUFfWNkBe90w==} peerDependencies: + expo: '*' react: '*' react-native: '*' peerDependenciesMeta: + expo: + optional: true react: optional: true react-native: optional: true - '@expo/dom-webview@57.0.1': - resolution: {integrity: sha512-lAKsME4SAq+8sf56oN0DX5TBYyruupoRxbWbD2xf9RnKY8y6x8eb9LCE5pxSN0qyWdqnp+0wmyWzDkKboThKAw==} + '@expo/dom-webview@58.0.2': + resolution: {integrity: sha512-bLkREoP7qL3rEuzxP60xG+TjdPoGjbnZfxkvYo5imJxGWfKMOf7x962W06Pu+WWAr4gcDRk16iA+Clg8D0zjCg==} peerDependencies: expo: '*' react: '*' react-native: '*' - '@expo/env@2.4.3': - resolution: {integrity: sha512-M1NXeZCA1mkMkYOyIe7PlyRX0/jqFtMoJgyblnlq/vpCRfmueFT7RnGSQG8uEFDF5WHOFGijAQ3fogPh3/n5Ng==} + '@expo/env@2.5.1': + resolution: {integrity: sha512-FXr7sJtusDKrrtfxenRdAwbqARTasYY1+3vL3FjnlvwiWzvItnSBRbcspF6AI45jIBLbi2GHDIAorzAXhmA1+Q==} engines: {node: '>=20.12.0'} - '@expo/expo-modules-macros-plugin@0.6.1': - resolution: {integrity: sha512-cpsLZE4rqkc1Y3eZTkxB98jrqY1YXgetmtxFt8q89jBRmk3quRuk1BZo+VcnCSObZardjg99r1k5xijEMONFGA==} - - '@expo/fingerprint@0.20.11': - resolution: {integrity: sha512-GC43EcjQwzpzNZISqmhvjKdi+6FTfxnC9ZxOeg6osCkYXJz94j107l0QpPLipg62khD5HAA5G5cUhevffbRC4w==} + '@expo/fingerprint@0.21.2': + resolution: {integrity: sha512-LlXmTyDMsTYL5gGIUbTZ9EOrGPTmykmI44tld6v/hU0aSQndbdoAtT+LHvKKy6oSMdm1yHgHd2YzuMU+9MwwZQ==} hasBin: true - '@expo/image-utils@0.11.5': - resolution: {integrity: sha512-KPQBTpmpAfy/Vu9y4wPW808/qtZxjYmyJg8cm2QCPAupp+qEWA3b5zmk0ulOwQ9OgeHxuCPgUqWgkwHFo7UsrQ==} + '@expo/image-utils@0.12.2': + resolution: {integrity: sha512-lz4ShWkci1UYI8JhBywQM15hamJ5YLG3kz9qjNNKS7cOq4EKkzf4ZZXLEzAPpQaN1j1wWpY2MtbPIYXFLNUHsA==} '@expo/image-utils@0.8.14': resolution: {integrity: sha512-5Sn+jG4Cw+shC2wDMXoqSAJnvERbiwzHn05FpWtD5IBflfTIs5gUmjzwiGVyjOdlMSQhgRrw/AymPbmO9h9mpQ==} - '@expo/inline-modules@0.1.7': - resolution: {integrity: sha512-Bz/khd1gIJqDkje7t5ejD5e9jFbm4xEJzWSwRKadRo6gruepbw1xJ3Eb+e58OS8fY1ZNQYjzZbspnuph67sN0g==} + '@expo/inline-modules@0.2.1': + resolution: {integrity: sha512-WvmG1vuVbd6Py6uwYw7NUHGlOSBdJTXU8X18qBhCYXMfV8MPic0QUuFuUZGTyIzs4xUB/Pk6qgCyUdxOlJStxg==} + + '@expo/json-file@11.2.1': + resolution: {integrity: sha512-UPhKoFCj8BcwgLB1rKQ1CuR/REITnZLiqxHEHOeH1tPsdXcHGtUDh0P5bLbr7oU0nKVdtJ5rzyKx8jniMQdESQ==} - '@expo/json-file@11.0.1': - resolution: {integrity: sha512-zxHWj4MKKMAL29ZQSY/Fssx4Thluk40JmuGNaeS078wy/NhlFhnVi+rHHunulE3xJAJ0CM73m8VK2+GkF9eRwQ==} + '@expo/local-build-cache-provider@58.0.1': + resolution: {integrity: sha512-V7zXjGgivtiqLe1oa6PQUvamoTf2/HxyavUrQSmZyDDUV6/mLQoTBrslRnj41OSIlIUqah9lxrcl759vKgMxqw==} - '@expo/local-build-cache-provider@57.0.8': - resolution: {integrity: sha512-SEdE0pAQrr90bRh3MNR0ZuwoIBw390cYdFgbn7Vk0Mtm9EHaBfP7kYj+2hXnXZJgOEm3/JMtfoD3rV7rWA9FGg==} + '@expo/log-box-utils@58.0.1': + resolution: {integrity: sha512-BUDoo1BUsSNmGonRkVWBNI6moKsZxH/Tkt9a1pphOBJQMdr8/1HbhGEB84YOwaKMpMXMWAK6cwu3Ip8ax3J28g==} - '@expo/log-box@57.0.4': - resolution: {integrity: sha512-IxwS9s1L2muj8mj8AQSuiy7u8OFJdc02NRFo2me/Tj6DiaeG5SREqmpBE4rQpR2cadqSg5jl8Qab8Cjie616dg==} + '@expo/log-box@58.0.7': + resolution: {integrity: sha512-V6KY7IoeRZ7GqMRXQDrBF5w53w+a3PWWrNXnjzzkDC1uiaf2RN8qSACDPbJRUxJloL7X8EXnA7Q29i/YozxYSQ==} peerDependencies: - '@expo/dom-webview': 57.0.1 + '@expo/dom-webview': 58.0.2 expo: '*' react: '*' react-native: '*' + peerDependenciesMeta: + expo: + optional: true - '@expo/metro-config@57.0.12': - resolution: {integrity: sha512-S62Lrq35HZqBFD55423pmWb8PjaiR/W02zQC1uECBmw1vTN8WZaFz4TJ0i21EeJzwfebMb9MLxL8JZ102Z6VbA==} + '@expo/metro-config@58.0.6': + resolution: {integrity: sha512-jznif78n3+oOjvhtvmSqBbnkOfabDvouAMIXQXC3FlGl75bygzRTYvB+L712fvZOJd+LSo1jcCg2Q3swUnJyBA==} peerDependencies: expo: '*' peerDependenciesMeta: expo: optional: true - '@expo/metro-file-map@57.0.2': - resolution: {integrity: sha512-tb50nSIWwKpRufSkGuivOK0FbUxv1Uwqptb0SzFTk0bkmYmcy3gIwnCbOHTfmrQDVndRhPEiu2SYgh9Z0PCvGg==} + '@expo/metro-file-map@58.0.3': + resolution: {integrity: sha512-BAYHbRc89uX/mfxkK7oPe+YUXrPKE0rn3rq/e0E/PimUBeTfQjs1Y6Y7A4gLPuDTtSczyiZzFFJiTyA4MlNl5w==} - '@expo/metro-runtime@57.0.14': - resolution: {integrity: sha512-LVpsfF0QOzlLSKlHYpxgW1cP1NKcYeaoalLO18jYHgqseSveEkb9VOffFpicTQ7AN03odZ4fgkUF+p5YpoY4yw==} + '@expo/metro-runtime@58.0.9': + resolution: {integrity: sha512-nWxcO3zFVIAMf9sw8n2meAy/pHlNQ1jbUe3aDYGun+slKx41sJ+xzd/Z2LFjuP2uzoyWE0v0zekEqzsA0fQ1AQ==} peerDependencies: - '@expo/log-box': ^57.0.4 + '@expo/log-box': ^58.0.7 expo: '*' react: '*' react-dom: '*' @@ -2835,21 +2841,21 @@ packages: react-dom: optional: true - '@expo/metro@56.0.2': - resolution: {integrity: sha512-Ld5AeYMCCDa8bLeWhfuLbZFFjlV3f6ORqyPz2glGh6RltIngMuLf9BTC2yvHFjkKuGxL5SynijmA8xmNNWn5iA==} + '@expo/metro@58.0.0-rc.0': + resolution: {integrity: sha512-9ZXNH/rppKQcoW0ycTSQqnKcjuYnutWf/6YkfAh1PBeWs+W1Nuc2uMTRM0qWNc9btbD4iHZKovru3gJqMgFzFQ==} - '@expo/osascript@2.7.1': - resolution: {integrity: sha512-Zn03EX6In7ts2lPUW2ESUSkEhEWQN1qqsiXjadtZMJOuZRkMiAg1ZQHuvz9DjByDWNJ2pBwAGyrts9lj9k389g==} + '@expo/osascript@2.8.1': + resolution: {integrity: sha512-SCi+6q6uOkGhiAn6AIP/OPFgaIq/iKD2oYpnAOg2rShHStJ8ey7wyT127RbOaZXmlcY/62rHOX1WiiMnD8u/BA==} engines: {node: '>=12'} - '@expo/package-manager@1.13.1': - resolution: {integrity: sha512-y/K+CaYYpZpNGZhSX4HyLT/vyIunFjNfyoxNysPBCefeLKI/VCx6f9LNPzrxayr3rCYO5bl9O8H+HRQK265Nkg==} + '@expo/package-manager@1.14.1': + resolution: {integrity: sha512-aw/VqeDaZsn2G5FxJUfWgWkdcl4u/JsNhlQakAEUhu5++4AitDprw4Uc0PwerH76V8Y34U/nVypL+YTVs/pi2g==} - '@expo/plist@0.8.1': - resolution: {integrity: sha512-3gTReGIUm0oRaMClsAJYxBnVPCl6fVpsl8HS+DTVxDhW4GyVyxg9E/Znm3BvcHtUJ51RJJI14pC1wvrNilCRHw==} + '@expo/plist@0.10.1': + resolution: {integrity: sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==} - '@expo/prebuild-config@57.0.15': - resolution: {integrity: sha512-xTbWHroj0PDmlbqvmU+zF9ZZxveJkiuyiPoeRJYRGruFHebRAWnoTdw5S7d/UCzDBI8ropGGu9g2eb2nMxtvAw==} + '@expo/prebuild-config@58.0.6': + resolution: {integrity: sha512-rnaPdJ+bSHRlJ2ElANH5P1QKtJSFSTxxR7FSh4qpwPfFJs6L3ozhOLP4R1z5oFCXq6MUQfYIDHb51rUfPAgDMg==} '@expo/require-utils@55.0.5': resolution: {integrity: sha512-U4K/CQ2VpXuwfNGsN+daKmYOt15hCP8v/pXaYH6eut7kdYZo6SfJ1yr67BIcJ+1Gzzs+QzTxswAZChKpXmceyw==} @@ -2859,26 +2865,26 @@ packages: typescript: optional: true - '@expo/require-utils@57.0.5': - resolution: {integrity: sha512-kTAXj9lDFEIPMsbAOGCGbjBbMF0oi7CqkYM79KOX0DDD9wSwXmlKL1z2h8OwsrBf7mbOo2DjlRvZu4BEjrIxGw==} + '@expo/require-utils@58.0.2': + resolution: {integrity: sha512-50w3h4s8eQze5L0PGfVAWGUWrT0ss9oHPa9INAIra43ScU+MP5s3b5qysvdv7mep9SgSX3+qdWIjcrOP5rNd+A==} peerDependencies: typescript: ^5.0.0 || ^5.0.0-0 || ^6.0.0 || ^7.0.0 peerDependenciesMeta: typescript: optional: true - '@expo/router-server@57.0.8': - resolution: {integrity: sha512-lEPGYoDmh97yyEcY/MFWQsfE7yIgMRnGDcnsBN7B6AiWBFSJIMEcGnO0aYPgY0ZjNWyJDi7Ee8QZRGqB+LhI6w==} + '@expo/router-server@58.0.4': + resolution: {integrity: sha512-zoHpJzp7ltEY5w9eCINlkeCZg0BvtXexj0SIg/B9YGgFIiGYQDbtrQYy6eDc1lUICQn6ntzql3lrunegdConvw==} peerDependencies: - '@expo/metro-runtime': ^57.0.14 + '@expo/metro-runtime': ^58.0.9 expo: '*' - expo-constants: 57.0.16 - expo-font: ^57.0.1 - expo-router: 57.0.17 - expo-server: ^57.0.3 + expo-constants: 58.0.9 + expo-font: ^58.0.4 + expo-router: 58.0.10 + expo-server: ^58.0.2 react: '*' react-dom: '*' - react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 + react-server-dom-webpack: ~19.0.1 || ~19.1.2 || ~19.2.1 || ~19.3.0 peerDependenciesMeta: '@expo/metro-runtime': optional: true @@ -2889,8 +2895,8 @@ packages: react-server-dom-webpack: optional: true - '@expo/schema-utils@57.0.2': - resolution: {integrity: sha512-fMu/jyN0l1Wzv7XkeWR4IYCx1M8ryui3FdBNGrWwbRgJ7EhxXxK8E2jxP2W3pbgUwUY0V3hG8+GyfCZwny+Lxw==} + '@expo/schema-utils@58.0.1': + resolution: {integrity: sha512-r5ox9st0g1IYC37tKD0WYiKH6RXout9FqjSwVv0nIhRYYTXhChJfzcMnJ90zkBznKO1lZVCqdO302YVYsm3qQA==} '@expo/sdk-runtime-versions@1.0.0': resolution: {integrity: sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==} @@ -2902,8 +2908,8 @@ packages: '@expo/sudo-prompt@9.3.2': resolution: {integrity: sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==} - '@expo/ui@57.0.14': - resolution: {integrity: sha512-m8Z5dCplkOOQ70lu/xfB67qhk00Muw4U1T9frHBIW3LxxJeJZQ+jOmV6vCk6O6zVgoG/ib1et7PeX6etxI4Rsw==} + '@expo/ui@58.0.9': + resolution: {integrity: sha512-uKwQb8zoDlbEw6jjHMA9OPzMVmo+sbnnKUhO/VNruaE3HF3swazCbrSRIomeznOVvyPP7EJsV5jXUrQgLAWzkg==} peerDependencies: '@babel/core': '*' expo: '*' @@ -3464,6 +3470,58 @@ packages: resolution: {integrity: sha512-ugvXJjwF5ldtUpa7D95kruNJ41yFQDEKyF5CW4TgKJnh+W/zmlBzXXeKTyqIgwMFrkePN2JqOBqcF0M0oOunow==} engines: {node: '>=0.3.0'} + '@noxcturnal/noxcturnal-darwin-arm64@0.1.1': + resolution: {integrity: sha512-Y0JXi8J4abYq88swQLqXOw0kSw0v6CfKp4tboyqPOWNVgQvUy14SMTKVyPLUpaKd0ZJGP8cvNTSQI9bZP7+5CQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@noxcturnal/noxcturnal-darwin-x64@0.1.1': + resolution: {integrity: sha512-lAaRd5TGFKydkYaPiDl/zGxg5hOZmJknEF0thMQHhe6s90fCcP/1t3XAaNH6czUbWV2dkhPggo9ua3Mm0KisGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@noxcturnal/noxcturnal-linux-arm64-gnu@0.1.1': + resolution: {integrity: sha512-871HxfCyTzrMz/OKzG17M4OgWdPwns9a3yCo+HALvuBsed+mtY2CliJvzoQhoRw1bdICaXp6LqUsY4KhX1A+Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@noxcturnal/noxcturnal-linux-arm64-musl@0.1.1': + resolution: {integrity: sha512-ehEOT/CgdZUpfuGVQ32u/nJU80SQVNql3J/vVTglH30MbGQlMA5Sd1VAHtYgVMtpXsIo4rlNhcvHIJ0L9by9Cg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@noxcturnal/noxcturnal-linux-x64-gnu@0.1.1': + resolution: {integrity: sha512-psTHW5aDNc3PpWFzQOJLmOj4oP3NZRMjpc8H1Jvu8vAqtVWakdxhICG5/q0jMkgY9iyg+mqdtHaLMeAImmCeHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@noxcturnal/noxcturnal-linux-x64-musl@0.1.1': + resolution: {integrity: sha512-MSdZTx5GL6hdG0UVrL7PHbLqDoO0Mz9mf6vwkhBbVYJGM4NY0ptNHsd5j5B+0RGjQgSMQX52tC96g8e23oqi8w==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@noxcturnal/noxcturnal-win32-arm64-msvc@0.1.1': + resolution: {integrity: sha512-Bq/C94sV38ay57QS4EbwIOamGNVXRkPVDc5Wg+4gvBjhJbYs+nfH05CpwRkQBgb8SpV51FQCLQfXvk59Aab60Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@noxcturnal/noxcturnal-win32-x64-msvc@0.1.1': + resolution: {integrity: sha512-D5ZuKQyxJd/wvf9qcVSCD69spzhoHNbaib/dJGpHXQLomrDBwtzYbPVxUwEBWAaXnTqme6/TEZdl/6sG4tm4wA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@octokit/auth-token@6.0.0': resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} engines: {node: '>= 20'} @@ -3793,6 +3851,9 @@ packages: '@oxc-project/types@0.127.0': resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + '@oxc-project/types@0.141.0': + resolution: {integrity: sha512-S4as7z0j0xQkXcJlyY5ehntwK8/wRkQb9Cyqw+J/N2rkWGQGK0SxD6X6DhQTc7qsxVTBxXbxZtBJh3mr3PtIzQ==} + '@oxc-project/types@0.146.0': resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} @@ -4256,177 +4317,6 @@ packages: yauzl: optional: true - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@react-grab/cli@0.1.44': resolution: {integrity: sha512-gMDYY2rw6OWajCcDlXSIgs2LC432YJXSb3Lm5yM187uhRgBYddoEVULi36h+IolX3r7jSb3ew7vn9FfI8NSo0A==} hasBin: true @@ -4448,78 +4338,78 @@ packages: react: '*' react-native: '*' - '@react-native/assets-registry@0.86.3': - resolution: {integrity: sha512-TDhgCZA4wjJg84d5A9swiOQYPIWSKEEVdg9IwMFZDupQzW/F3QoLUrfAJOcalgqTDA9/buTB8awhE3Whwg6u9Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/asset-utils@0.88.0-rc.3': + resolution: {integrity: sha512-G3P/3lF1bvZoT4Za87UiVJCpTNNF6c07sTNINXYiSxXDpPiM8piisgqdgueyy90cKH6ReL28y2S8glRiG+jkeQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/babel-plugin-codegen@0.86.3': - resolution: {integrity: sha512-O6Xza4JBGPIU8J7YbKTyBoYL4thpy8jMW/oaLDWdAyOwYHKIjK47pAL5HUEbOe2bWz2PEKjbYRF2ApkJv1ottQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/babel-plugin-codegen@0.88.0-rc.3': + resolution: {integrity: sha512-v68EZUjkcs2ZLL1ayA2aQ79imy7BGlc6uAteKMDhA8vf0QKT92YHkSFMGA1+df38d3/v3R+AB6X6XFhixQ1EEQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/babel-preset@0.86.3': - resolution: {integrity: sha512-/eqs/Hy9RZRcjdcs4wj3Cqmxvtb3NM5g+Uuh1RIvsjynMO8PRsrVWWLWgBcZL/jYUo+ogXd2NFB0W8L5Bg89xw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/babel-preset@0.88.0-rc.3': + resolution: {integrity: sha512-xkAmd1gSQWjl5QnY0YFuMhjykdABljvuUY0McQHHLf4GJHEcpwuRPf3kM5lDq8p/y+Ui2iAbGgQsGExFY6FV0w==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} peerDependencies: '@babel/core': '*' - '@react-native/codegen@0.86.3': - resolution: {integrity: sha512-Ux4jHi0fh+bdtVEcL0gaPLbY56V+SvFUDl/8sRAE1jdb4k+o7fT/4Nc29yz4X+qfjstkSqObQTMBGhdzxH9JvA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/codegen@0.88.0-rc.3': + resolution: {integrity: sha512-fjDCsaVPTlrYHelSogo/J9RbeeJ+dfokyw57VdtFa3HMWssCSqBmgnSoKKexQAO6U4fppAm91550DC8+02pL4A==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} peerDependencies: '@babel/core': '*' - '@react-native/community-cli-plugin@0.86.3': - resolution: {integrity: sha512-qSDL9LQc5mZSZPNczT95WU9YQuPzxBklgON9vLhhqfI0yWIwKInqFx88dQ/uiEXBtf0yossthaQIqA4Ml6bF6g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/community-cli-plugin@0.88.0-rc.3': + resolution: {integrity: sha512-wfchdOOL4EM12jQuDY75uG9/pJ1dMckugJmAkLsyHY2akhjImdn7rq0Ea7q2nLK0talq56jTklpXQZVoVvyrAA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} peerDependencies: '@react-native-community/cli': '*' - '@react-native/metro-config': 0.86.3 + '@react-native/metro-config': 0.88.0-rc.3 peerDependenciesMeta: '@react-native-community/cli': optional: true '@react-native/metro-config': optional: true - '@react-native/debugger-frontend@0.86.3': - resolution: {integrity: sha512-TQmeofQ0PcuylhhlleOeuzHYZfbrgm3gayXzowqUEzgRisTm1D40/J3ggqs7XkQi5HP5ZA3n8dHmKL9vIzPcsw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/debugger-frontend@0.88.0-rc.3': + resolution: {integrity: sha512-tv3DAqm5oTjQ9sYkr99UMKqc+VfoCZo13ZobzKD7oDRl7b+RT9wtyUiQrTuRQLrmadJ+TfU11G8xnyVmjHC/Sw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/debugger-shell@0.86.3': - resolution: {integrity: sha512-O4ds+J7xZfxkbih9T+cAGegBdvKSPKYJm/lDgC9CpEjFMkmzWTpVLU3Qsv9sqZuo58z+sGhIcJfPsCFFWHpqbQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/debugger-shell@0.88.0-rc.3': + resolution: {integrity: sha512-ECf/bl4c/eGd77tNQnCizoLqYiOTyOQ1pU7SzVGI4Nql+aZiNR+lGaz3CJB1ve4+g+00hXTyiBjPjOmfNfdEYg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/dev-middleware@0.86.3': - resolution: {integrity: sha512-LiEPTqTg/63bYUnrPyHLfjTDCNhA/+CUqI1+DsA9tYyewtSbULd5awsva6SgE10I+2iMhgKXS3ymkhU/kSCrGA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/dev-middleware@0.88.0-rc.3': + resolution: {integrity: sha512-lM7ZJ/SZJAEHtN+TUlA4onk2PxRAIFSM/9v6bxtk6jkeXQyNIxFhXkqAzkI2vXV2ImtRv7XXjs4pwKkZ1jxJxg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/gradle-plugin@0.86.3': - resolution: {integrity: sha512-lxmx0GqLEWRIpZfpYFXlYVIs3ENQwaW6Vmp6oi29l2GoQJ1wZfFZRdMimDWlGEk8LKfHar3QH3iaPMkTcK9lEQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/gradle-plugin@0.88.0-rc.3': + resolution: {integrity: sha512-mH7obkxTQ2s/7hANYIaGmZWXNgVIobbZNuV1YpTvWRZrwtLsl57scHevP87c6+j9RDYjzMSLIfHvfqDFo7cqoA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/js-polyfills@0.86.3': - resolution: {integrity: sha512-eYIJ0es967+tePBFQDnl/gidVFxLns3fnbiK6rxscQrGodvuUO6hwxpQnfNynJ8MjbbndImXihXjcnJdc7SzJg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/js-polyfills@0.88.0-rc.3': + resolution: {integrity: sha512-KONuwN2lvrLopOWVgLTFNwx1cwdlS5NZbmR+fQY5r6RvkHHvzbN4JqnfP2oQB0IGLxjJZPN0ljfhhPiCZ7YMdw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/metro-babel-transformer@0.86.3': - resolution: {integrity: sha512-0nlwVkG0uT9o72nrGTKUz/IqDnCkM4zE0ihe4r+OJcxH93yBdDm58AXJ3EXZeSjv3osHEFXU7ceajdZiS34mTw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/metro-babel-transformer@0.88.0-rc.3': + resolution: {integrity: sha512-ekhRzsHa13fDZYTSfq5SWS88wcc+2Magy3g2oG0fup7beFrbpLxGzIm1bpBNg892htwvWHtLDuV4CUvFKka/EQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} peerDependencies: '@babel/core': '*' - '@react-native/metro-config@0.86.3': - resolution: {integrity: sha512-qdzDMepV2xdUhsO4XC7idnnbt8K6+Hd59AjeK9y4KS86fxSQq5oL0TAbqUuajDGR7beNQoYTuS6AowN/zP0oaQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/metro-config@0.88.0-rc.3': + resolution: {integrity: sha512-nyJSwizwYxZtwHAaL7PFJ+33FN9Ho9q/5h931VtLTQDr6OxrWu957K2il9Yzd/k5wAURpv+DDB3Oagl3hl2HhQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - '@react-native/normalize-colors@0.86.3': - resolution: {integrity: sha512-Cv3CDkprb67GrzuaS9BGbBJC/6G4lIw3nyKOHRKTqTTum4bn37y5+R0Z04L8mcbQN85eEohNrRwb7IOM4j6uvg==} + '@react-native/normalize-colors@0.88.0-rc.3': + resolution: {integrity: sha512-el4NZ16vfh2quo56hB5G8cD8Bbk8N2+hamMfeaSWE5XCQC4vyTWGrE4FORjTdLAjv4Uh8LMuX87iMgwt2adArg==} - '@react-native/virtualized-lists@0.86.3': - resolution: {integrity: sha512-1j44NEyNn05Ut40vHAmoSWbsIcybFkMAOBTwQt1PrESyfSS+qBoyU1LGIogNva0VIa0rQyEC5PzbA7R4/7Nhyw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + '@react-native/virtualized-lists@0.88.0-rc.3': + resolution: {integrity: sha512-0vI4q0kjrS3HPn5pg5IXkVUAmNBS67ZqKzhaAKfuxvQ3Xrr5Q5LOH7u6DphTSQ+Dy2GYeQUxSN1XqCUbpbcxxg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} peerDependencies: '@types/react': ^19.2.0 react: '*' - react-native: 0.86.3 + react-native: 0.88.0-rc.3 peerDependenciesMeta: '@types/react': optional: true @@ -5379,9 +5269,6 @@ packages: '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - '@types/hammerjs@2.0.46': - resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} - '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -5441,8 +5328,8 @@ packages: '@types/react-test-renderer@19.1.0': resolution: {integrity: sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ==} - '@types/react@19.2.16': - resolution: {integrity: sha512-esJiCAnl0kfpNdE69f3So4WJUXy95dLZydX0KwK46riIHDzHM7O9Vtf9xCHW0PXIqvgqNrswl522kA/5yx+F4w==} + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} @@ -6058,8 +5945,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - agent-cli-detector@0.1.6: - resolution: {integrity: sha512-vKrPeEVN3upDF3GjWxsWBbwQgMtNJ8VB1cduPvK3svmmz4ENpS7yaPxbogsbe3w+xp9xp2Cu+0Ar41rjAR4+lA==} + agent-cli-detector@0.1.7: + resolution: {integrity: sha512-d8OWDVdZMgjhLUT9ZPgSv/BdFFF9pVuscC0JdUSz3bjwE15gcp6u/o0/JooM2yyAWC49KThFhXlgTXRa9B7yng==} engines: {node: '>=18.18'} hasBin: true @@ -6220,10 +6107,6 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -6307,21 +6190,18 @@ packages: babel-plugin-react-native-web@0.21.2: resolution: {integrity: sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA==} - babel-plugin-syntax-hermes-parser@0.36.0: - resolution: {integrity: sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==} - babel-plugin-syntax-hermes-parser@0.36.1: resolution: {integrity: sha512-ycduwJbvdvIMmVvlAZqGggS+pm5Eu4Bk9pcV9Sm2Z4PJNRVsKkv0g7vHj+LeuC1gHTeF67sJXFOq61IlqCa2hA==} babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - babel-preset-expo@57.0.9: - resolution: {integrity: sha512-T19biGOBTnMp161PyBqWOoSIEeZug8/EjtuUdVob8JPQKZMTalHUQaQt+qtQQE7XsEkZJ6erb3k0CohneTFzQg==} + babel-preset-expo@58.0.6: + resolution: {integrity: sha512-e4PqE6comKx0CKZo2l1XlNoWE9mfabQvAHDk6CvqmDWMEh3vIJgBubZAbdBONsxaUqKON2SVnXKmmPD01iW1iA==} peerDependencies: '@babel/runtime': ^7.20.0 expo: '*' - expo-widgets: ^57.0.13 + expo-widgets: ^58.0.9 react-refresh: '>=0.14.0 <1.0.0' peerDependenciesMeta: '@babel/runtime': @@ -6537,20 +6417,9 @@ packages: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} - chrome-launcher@0.15.2: - resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} - engines: {node: '>=12.13.0'} - hasBin: true - - chromium-edge-launcher@0.3.0: - resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} - chromium-pickle-js@0.2.0: resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} - ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -6873,6 +6742,10 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -6911,9 +6784,6 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - detect-node@2.1.0: resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} @@ -6937,8 +6807,8 @@ packages: dmg-builder@26.15.6: resolution: {integrity: sha512-nr5vQxEhM0REomp1qiHbc6V99yrfBZy+wUU56VXADfSOlLj8PdLqsHiRe7b+FbqKesiyv4ax+k1GVwGonYKuCg==} - dnssd-advertise@1.1.4: - resolution: {integrity: sha512-AmGyK9WpNf06WeP5TjHZq/wNzP76OuEeaiTlKr9E/EEelYLczywUKoqRz+DPRq/ErssjT4lU+/W7wzJW+7K/ZA==} + dnssd-advertise@1.1.6: + resolution: {integrity: sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg==} dom-accessibility-api@0.5.16: resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} @@ -7314,46 +7184,46 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - expo-application@57.0.2: - resolution: {integrity: sha512-q31YwcXyymviAmdrtDfAg3Dld4VMxLCNAfgMHip7vZpPX4lzF/AfwsywqBJUAjQnJknzaNAkzqvMVjO5XmKYDA==} + expo-application@58.0.2: + resolution: {integrity: sha512-N1ivhudcdS6KmEm8S9W14L3WVgFnCUv85MU1YX+AYauJcs9IZWRoM7Wl1JU+PUUYvbVGLHoXNpu0aE3jVTdkFg==} peerDependencies: expo: '*' - expo-asset@57.0.15: - resolution: {integrity: sha512-ZoiUftQb1Nn1jvL6l1kZoUXvgRCx57tMQYxSsp+g4ZvY+jgVWp/THruXOtPtZVdC/WWZxPUTct53bfAm2EPDAQ==} + expo-asset@58.0.9: + resolution: {integrity: sha512-31fMfET8PyoCNGKmyjOY6fBTyTO7du80EjtrzZ/TsT+9zincWMUGwBWeby/fTXPHMEVgWQAiU2sKEteWEw8+Tg==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-audio@57.0.4: - resolution: {integrity: sha512-TLP8rt1UvUDzgxGnyQ0TR9hV6tNP/UJQdDu7mSK+dgEydMFoptq55D3hcUoB1gF39f3/3AUuWfOtpGM+4N4X1A==} + expo-audio@58.0.3: + resolution: {integrity: sha512-BwH1calLvev1jfU/ZF3GIpW76LOhevLXk+nur0FZRZyiZJYxYvvg6scO0+XAt0d7pk6/kiPIirPHFlWgb79fpw==} peerDependencies: expo: '*' expo-asset: '*' react: '*' react-native: '*' - expo-auth-session@57.0.10: - resolution: {integrity: sha512-i1RY93LouEgal2e/Ly1r2Ytwed7/y6i4AUShVj4Gg49h/Okf8QpZO7XylwL43IHfKRrKkqapRDEN8mWe7z/HgA==} + expo-auth-session@58.0.6: + resolution: {integrity: sha512-kTTQcZ2WgFxJlV2XtlBJxikADl8zPk1T2tTcC5c2ZOpjfAXHPDF/4pC9tfyYxNe0fOjCq9+t6aVL5X0uzZdVmg==} peerDependencies: react: '*' react-native: '*' - expo-blur@57.0.2: - resolution: {integrity: sha512-Aoud8H8lmlNkbRufyvRLefmGFELdBf1n5Te/Xm+Zx8ORINH+aXL+gKb5mbftFSha860+I7pMArz77TBYz8HDVg==} + expo-blur@58.0.2: + resolution: {integrity: sha512-2WKeR2FCSwTjTm+D0YLoLy/6rR583LYxlnhkB04zVkzWBiQKYCnOaUaOSsjQO2Nr/6ZpECmwXDhw4yzIuHZARQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-build-properties@57.0.15: - resolution: {integrity: sha512-qZe9pnxlBpHT7SSNDR2a3C+P34xv67Ep9I0Erh+3xCczGlokyRd4pu9h0PrBdsVlr1d0QREQ1Do/+IgrIWkQQA==} + expo-build-properties@58.0.9: + resolution: {integrity: sha512-NJ2Zf1/ELtXVng9J8EH6F7zSA2tfjOyaq4itda3yaiSb5a5lgLjLg1+USwPo628HI/yGILGyOwmC8zxegEUyPQ==} peerDependencies: expo: '*' - expo-camera@57.0.4: - resolution: {integrity: sha512-MqbbQ63O+cA8JbK3lfFHiD0f2jv8jB+EG/ILK6f5xnOPV9IR37yaG5+lGtRZNoOeYBzGypyOi17USItleMyuGw==} + expo-camera@58.0.5: + resolution: {integrity: sha512-UMc27NClJ5xnu2m/6Kz5zynOxJ7LluY0lgbu/TdxDZgGccjfM/myfLcO5r1FXaW84Llf3vTveG7SvwuRsNWIlQ==} peerDependencies: expo: '*' react: '*' @@ -7363,101 +7233,103 @@ packages: react-native-web: optional: true - expo-clipboard@57.0.1: - resolution: {integrity: sha512-HWICri4+1ao7S6QEfcorxVumXDiDnx1guGGewjZgGJWLGxFYs0RgH8ujBs+lkTzBkMmlwADaWSlaesR+nDJt5Q==} + expo-clipboard@58.0.2: + resolution: {integrity: sha512-AiL1yU6iLX4sP8BZZyLzsSCo7XWysIBgVAck1vTqIkZm5PcVBeKiDgjXeJzG8nHBpti+ReeGhxbCaMQe7VbyMg==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-constants@57.0.16: - resolution: {integrity: sha512-HG3yJjGZo2BPTo2F1sBoxdJZRwX7d9C554EhKn8m12K62pxGolCsvPSoh/lQf95OEP9vO34wwXB2C3QFs0KG0g==} + expo-constants@58.0.9: + resolution: {integrity: sha512-+EaES5uHt3t3kY4VPsvM0uiOo0sjiMKuxGKqdfKaNbpCg3FI5D3qfQbgDHf5fbM09DIfXSbymKeiZx/JKQgzng==} peerDependencies: expo: '*' react-native: '*' - expo-crypto@57.0.2: - resolution: {integrity: sha512-OGLvHK7Hb7qsONMWGB9pJw3n+iY4OnZQmM/KwQEHRMrrOmNg0Lxj9+tp9bj46aAMMzXx0FTVA2jUKoplpXPnkA==} + expo-crypto@58.0.3: + resolution: {integrity: sha512-i6es/jfng4LDnmgVmHMCsFPA0ns3Iur9ypH+reRLVqH2Mgi9spYqZgpuhpX3gMyu0rKYylLz2YM8n5wxvhNp7w==} peerDependencies: expo: '*' - expo-dev-client@57.0.16: - resolution: {integrity: sha512-Txss9sgzEFI0E+4I34E76vPiukeVDHnqCj0ZXy8SDijVM31/P6MCNniVbEZk7MBPQclD0aopfuaCFtkV8+r1sw==} + expo-dev-client@58.0.9: + resolution: {integrity: sha512-JQPBDw0bZqZCqbOVxbphTaJXdlzuHcP7rXBxakWhotNy8nA5Ek4p6E8pIJu/OMWSLleoM0Dgtz05H/ShEHBItw==} peerDependencies: expo: '*' - expo-dev-launcher@57.0.16: - resolution: {integrity: sha512-jaBr6q4A5js/r465m2mRxN8A87YOi8I6PiIt8XIt4qfQWDgw6hqGovaF1AVFGT1Z5jxkjtgK8WNz/rAeypjqPQ==} + expo-dev-launcher@58.0.9: + resolution: {integrity: sha512-wf7MDFbPOoTBD+ZWcFKyhxw+g1jghPL5yl9/r3PZmTiprpoMIZQXUBGpmnAHifJbA1Fhlhzm978tGU/Njr2t5Q==} peerDependencies: expo: '*' react-native: '*' - expo-dev-menu-interface@57.0.0: - resolution: {integrity: sha512-F47VdzOHYc19FhI/jBgctpO8a5UskTIxG6a1E5t3W5gF8VImuvBQffdXXfLHhsuCl7dS3v3U0R45cleeVXO1Zg==} + expo-dev-menu-interface@58.0.1: + resolution: {integrity: sha512-XdjO3ZZhEq1dXm15GVtzQ0SXxSTPguJIDZib3Z8tAf2jLxfPUlQObgO/0hdnw7ssEBhTT2jQo2HAfnOSGUfj8w==} peerDependencies: expo: '*' - expo-dev-menu@57.0.16: - resolution: {integrity: sha512-KzMHtAmnr0GqyU6MCrKLzIo/AfOjcToGhzK+pFeXlcqSPOrPJbTGlZqQ3E1o2G2jZMs+M1XvXh/VgnRyJUaRGw==} + expo-dev-menu@58.0.9: + resolution: {integrity: sha512-+VJMHf6XeGgVhQsJY+9CqKP2JTAv6n8Ki5NJt70BF0iqM5LzWa+/vwRna+HcTVYPA1KfHErSfL2WlLJT9LDNyQ==} peerDependencies: expo: '*' react-native: '*' - expo-device@57.0.1: - resolution: {integrity: sha512-jyEMDUticH+dhcL3GHa2aiifOvGXJsmb3oVT2R2q4i8bN7Bddy61+NkpMmuS2VAZrvoLQwf0TJJ/1vi1ukvutA==} + expo-device@58.0.3: + resolution: {integrity: sha512-sK1xb02joE79KQ/c9c4oCaMhErjwUoL7IfInImRyxxmuEfKuzlNldBV61mahIrT3UyvYZBEwMM0Sx76Yqn7izg==} peerDependencies: expo: '*' - expo-document-picker@57.0.1: - resolution: {integrity: sha512-qBwM5oxDZ3I9kwFD3pUE1oK/WNv9artoEKO6UpqhQgNRr0XA1ALRVWYjkF4+ge9lUNDRehjTm/jenINkzqg84g==} + expo-document-picker@58.0.3: + resolution: {integrity: sha512-7oNPAhvzjGoF3Yhmkpw8GppXT05I0RC6qzskW4wbRgDFhuQRhE8eUvYU7T/Bq6NX1ERu5TUbTI0QS9zo3DO1SQ==} peerDependencies: expo: '*' - expo-eas-client@57.0.2: - resolution: {integrity: sha512-EfFiqUr0o9TvTOgMbqDiV1oIdG/d7kirhqtwa7roGmm9wF+CpXUz20d9YGzO6KzJWUYgdUgu4B6Ocv0jNJUdnQ==} + expo-eas-client@58.0.1: + resolution: {integrity: sha512-FkomAg1uLen36v8U7jyzMKbdrMjKRSufB9qSCnhWnJynYkeWK4qAb9UyJBD/afkbTFQfq+ARImjM7IAi3V+2NA==} - expo-file-system@57.0.6: - resolution: {integrity: sha512-pm8PMYEW6BnVOCBJ7df9FcDmQtE1tqImuYphlfYe1ipQRLYtdCayRczJcbKIsnB3mqEyp4gC2gWmMbsAsAOjVg==} + expo-file-system@58.0.4: + resolution: {integrity: sha512-w7Vuh1qA4fkZOSR4Zylvdr6bgOiH5p1hvfrnNlP+Xqb1x5h8Mu13yvQKUm4A1yc7BAeZ7CXu7//dw5hDEevFUg==} peerDependencies: expo: '*' react-native: '*' - expo-font@57.0.2: - resolution: {integrity: sha512-eWR0CAdysgVqg8VewJ8b5wKh1pa6C8YShIEU3SP0+hlSqOk4djUwuJjn3P04KHVzL3hws9FrUuPxCNmd4TGung==} + expo-font@58.0.4: + resolution: {integrity: sha512-AElYv+6hg7xgf8x7yL0zP8D2QrJuASU59iKC+yLd38SM6AvWFMlgBz0fkcgWtZFH7QI0Kz1WP+WsCQd06wYxBQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-glass-effect@57.0.1: - resolution: {integrity: sha512-m/n8maxqNcHk6ZDhuqXBfD5Kt1Iz3M8xykVgdB0iSCIXvF70IqWXmQhX8Psswhrp8eZ+3r0mAD0Jh/2gFA3QaA==} + expo-glass-effect@58.0.3: + resolution: {integrity: sha512-NoFT5j2uZecNsiDAd47z37PWYTxNJnJMrVYiAU+SggiV9K91Sc0IuIcMsuOM4sUuPBQdSTs8/I9KXk5M0Z2O/w==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-haptics@57.0.2: - resolution: {integrity: sha512-vPths6zTxxaGaemC7D1GKbw1iOnOAAL5oAcCFVSgVNWnuLCBefL1LkhRBaJsepiMXRh2y3vwPiXkPaf6d16blA==} + expo-haptics@58.0.3: + resolution: {integrity: sha512-5chRroIhYhB2CG6Ce7sE82q4EATF9O4G7oyeUlDumcVAZzpNWWJkCZ7ucajyHOj2Wc/rArg2h7jYmwI3sgxnNA==} peerDependencies: expo: '*' - expo-image-loader@57.0.1: - resolution: {integrity: sha512-uhrZKLT/cTl2mXyR28kPpVkS5O+PK9N1QA/07IFM4f5T4g0lTW1JHT3NEWwEEsGFldPmVX4j7LwUVVZxE+woug==} + expo-image-loader@58.0.2: + resolution: {integrity: sha512-anioFtqL5sl7556fw0vZOJBqICq0cpQAUUeQlFR40e9OJawCguWAs/FFpJYNX94DUYrp8YzlacThSWNyh0YPGw==} peerDependencies: expo: '*' - expo-image-manipulator@57.0.17: - resolution: {integrity: sha512-VpM8qAotTeSIobIAL8RAIDrZKL0jQBK/6O41NnwmdT96sd2wT263DlTbkvQ6RkcFrR9+NZiC5Um7FDBK+jFneg==} + expo-image-manipulator@58.0.10: + resolution: {integrity: sha512-JWapRwmOUq5RaePB1WKlEDgX/MewnRUeM6MKE0W7zEvbkyFYVn+4swUNOP3WDjDzu+To+878bqt7hcRcaqWzzA==} peerDependencies: expo: '*' + react: '*' + react-native: '*' - expo-image-picker@57.0.14: - resolution: {integrity: sha512-NK9XBQqOtscbB/uRts1Gm7Oki6odMN3FQPWD6fSKmNUfKM69O6kcgU25lEXFTSLZ7sLl+AopHa2X0uILd8rjaQ==} + expo-image-picker@58.0.9: + resolution: {integrity: sha512-irYps0kkD+t17jHhBbQfm5Y9NbWXxULGyZPP/y90td3LE5zlFvFzNCj8Qnfif+ZFtg0QaL0T2fb/p5NLbfFA0w==} peerDependencies: expo: '*' - expo-image@57.0.3: - resolution: {integrity: sha512-EYfV8tIQxXLQPHhgZxc+bESUn2NcVw1U0RM28qqFeFfHyD1sBpIYJC2JTy24OtfBowYVoUyTvgf2ykWydiZVCw==} + expo-image@58.0.8: + resolution: {integrity: sha512-kRzMdDK+Cp0Iunz/psYnFDvt2MGTYA2qsZrey+nkH3XrtjTJVRD9hhdnHh35vLO3LXJsUNXfEvGnNV+ghnk0Hw==} peerDependencies: expo: '*' react: '*' @@ -7467,32 +7339,33 @@ packages: react-native-web: optional: true - expo-json-utils@57.0.1: - resolution: {integrity: sha512-cgTe1NqzQdYs/WN+3nIY5IZg8s0pb0xaTUbhYvxQDn137GbwRfHoGM2se3m3Vsl4Qu+B9G4RPEK5WJDEU2Do7g==} + expo-json-utils@58.0.1: + resolution: {integrity: sha512-jNHNElOUPz2/vW3CbDKRn6tTF6eE9wwVbh/Isnqp5c/CdTcONzFVR3YHN3WQ05PnkmieyEqVfeOusOd1X9FDtQ==} - expo-keep-awake@57.0.2: - resolution: {integrity: sha512-GqgH746wtJImmsbyHmCQoi7cOslKuWQBbJHXr53S35Bpf5UvxCAztvnitUEd7D0QvFN2rvkOhylbZpgZZfBLlQ==} + expo-keep-awake@58.0.2: + resolution: {integrity: sha512-UIddpQTJrYq/qsiuFHRJQwb1z1jojQ44XV2o6+bSuxLFKwO4KXp21to2GD3RkRFYLKdrEm98FLbzD9KpALkdKQ==} peerDependencies: expo: '*' react: '*' - expo-linking@57.0.8: - resolution: {integrity: sha512-gv0ZNaF7tILbcvX8xinNbQr6GIGQStxeUAJseweP+LjC9ped7Wl6EeyIMBlDR83U6Da+8drVeqBQSMvwAXgytA==} + expo-linking@58.0.9: + resolution: {integrity: sha512-EhA4cClb/rB8idwcrg0zQvgPxAiB0rnjy/zF9DLxmxxkTjV1Y1X3XphfeDxmoWNNf1gL9E47K/R6wsfJcni8aA==} peerDependencies: + expo: '*' react: '*' react-native: '*' - expo-manifests@57.0.1: - resolution: {integrity: sha512-qB/mDG2dYdl+EvUeQuqP8KFYCFgFCQjJYdWIHo8SFBgDzMYmdF286DFY2M1M9Okr99wkb5M4tgA3aCcwv3aEQA==} + expo-manifests@58.0.1: + resolution: {integrity: sha512-fVeJJ71Fj8FJgcAUggn6QIsm7CTxsXFgekLl4pEPHgON6fmcxog63FGO0sisQ3F6yUWFR4nn8iJmgBp1Exs7ew==} peerDependencies: expo: '*' - expo-modules-autolinking@57.0.12: - resolution: {integrity: sha512-Q8KAlq37nLKsQ+HsS9NpQVpd5jCgqtu694TDUNHBUBpV9ViD82mRBh8Uug/h68RG9xnLS+kuL4nYaCuFRghHjg==} + expo-modules-autolinking@58.0.6: + resolution: {integrity: sha512-1O707KinH8UCUzi9JNeFqF87BJSh1fGgpwjdI/NzBhG2IoHAFQ1ngnpyqF6ikr/o01aGoBgjdCRRLfzEnop/IA==} hasBin: true - expo-modules-core@57.0.14: - resolution: {integrity: sha512-Cg3aQnVsQhZcMOF/RFgPGzMuhIak5W9eR9ecwmFSeQ813r4/49ut6RMA6PqUuUKuPCUIRqnBAHfSyTm1W9nfzg==} + expo-modules-core@58.0.9: + resolution: {integrity: sha512-0BD1t8aWXPGGA+222KzG4MA29iZVqBNJWCKoPKFwD9ab7x9wPkazLGifAp8m3VOYKLLMbzYD8uS9XTJdiplduA==} peerDependencies: react: '*' react-native: '*' @@ -7501,19 +7374,22 @@ packages: react-native-worklets: optional: true - expo-modules-jsi@57.0.6: - resolution: {integrity: sha512-WK0xFEe0FdZTCLCdfXK+HVNYfAmEbA6goecRxqjr0gh3XYRKAr9tikxqcM0ItLQoEPKntscPZhWcPLGvr97Tfw==} + expo-modules-jsi@58.0.5: + resolution: {integrity: sha512-5UMYPOEB1amqV7SCQKxJBvyZHycW4ZIeP3cwkv22pSE2nx3Hj6IymNz34TtIrCMcJAs6mO7MtG5OUsgwTp+iTQ==} peerDependencies: react-native: '*' - expo-network@57.0.1: - resolution: {integrity: sha512-ndg+FbDDlz6XTpQ6aVuVgyvrYQwMkpcUAvZIXbwrGBbLTSWNzYC/gawYu1BAeDN7O6JTGY98GBVJBov/JH7LgQ==} + expo-modules-macros@0.14.0: + resolution: {integrity: sha512-R6ODnfK0Za+pSZZjv0SuOTV2YkxczeavvrsLv40gueH3U7QJ8H5OlD3kkFqyT68UzDLRJhwF52D884egtNH7Rw==} + + expo-network@58.0.2: + resolution: {integrity: sha512-+Ek0nuLcZmW4f35L1lg4vo3lpotV0OUehFj8y5z0w/VEAw3WOeEzXh7Eo3TS6lIvsbyIJO7woWx8fYjMbGnhbA==} peerDependencies: expo: '*' react: '*' - expo-notifications@57.0.15: - resolution: {integrity: sha512-H91z4WSFukSQP3dThgh6PCPFrT6VHeR+J2f7CuCOE72JV7YEGcBCir103QY58ocKsdgkodQpnkTU2m8LTHkWLg==} + expo-notifications@58.0.9: + resolution: {integrity: sha512-Ygi1bvJKMiv6wP0r9b3WzDkZy28EbIeagNvxyQqcy6FoyuUpAIXbH0IgnaAjK3czPWin78jC3GsDJYeZbHFPDg==} peerDependencies: expo: '*' react: '*' @@ -7531,52 +7407,52 @@ packages: peerDependencies: expo: '*' - expo-secure-store@57.0.2: - resolution: {integrity: sha512-PhrPMKnI7YSObLEQZOoP9evB2ZOCv9kFuG2L7cZfNlOwWjGbir711PlppkXVoM3JE8vamDrTqzMLGv266FhJJg==} + expo-secure-store@58.0.1: + resolution: {integrity: sha512-jYKTkbXOlKrt3DiDw+f/EGc70UfyWNJgQiBEQ8ocyEpUehouyp9GcKza3gWixgLV8CWaCx4RtxiFQ5pFWaj0XQ==} peerDependencies: expo: '*' - expo-server@57.0.3: - resolution: {integrity: sha512-aK+LdKzauHSGmsOStZtyxdzv0zWssCkxTw3m4QuOhfDSJsZaMRTd9O41d8ixU/QfELTbaJ0oRNcF7JFV/7O9YQ==} - engines: {node: '>=20.16.0'} + expo-server@58.0.2: + resolution: {integrity: sha512-QOdIBRZ7hEhlKzDud99/4YPggg+rASCD901PuuDy/oHzSP+eQKs2B4PDwzwfYvtelDA45nOwJsyCKnBvwpuJZA==} + engines: {node: ^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0} - expo-sharing@57.0.17: - resolution: {integrity: sha512-p2B4SMeNsOv6hm1NkrxRlncjwu9mmLfi0drLaEyX13Rxn4DdDFPhuaezpOK7XLogTsmWGpfR46uq6oHMvSxbfA==} + expo-sharing@58.0.12: + resolution: {integrity: sha512-2uwxo2+9W6WzA87FnBiwCAWkrBAoNUrNY7mJHA5k3Q5i/je6tH2N65kl5pACpYEIOOShQkOAd4zz7DVc23JydA==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-splash-screen@57.0.8: - resolution: {integrity: sha512-BEsrKg4niYBZa5AFzWRyGqxA4ZemtBOPwbCy+C336iGYYPuZYLEgWJGmm2xD1gRfCdrM/TP+l2ONd86Zvk3KyA==} + expo-splash-screen@58.0.2: + resolution: {integrity: sha512-rYs8/d8GGFKBfj1cecr8/87nfUcdSmqQq/enm8Wmv1IuC3l1dxnxFRWlnz2KORCYLUw42M2vNRqlSU9ETHt8GQ==} peerDependencies: expo: '*' - expo-sqlite@57.0.2: - resolution: {integrity: sha512-5KVbT7BQFZlIcQBXKWvwBERK3ODF6PSqct27GQKukZzAjsx2B97R+mwtYqrTUtUbw71VJrQrdr9Yl2OWYC7UpA==} + expo-sqlite@58.0.7: + resolution: {integrity: sha512-0ge3jryvlzEDyT7mXPEpTaqIIT65+n2noQfxBrWMdmSmuqL4L6eAYw/81C8UrXmDM97Y7vmmdR3abkMdN/a2mg==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-structured-headers@57.0.0: - resolution: {integrity: sha512-//t9UNPbJSEysc2x4VKJG/u7Osvv5DYJWsET5bqt/B+qcD1by/JXvSQzX3Q/YAgA96xFPontrz6OAPLbO4JKEA==} + expo-structured-headers@58.0.1: + resolution: {integrity: sha512-wIduvAIUdGQk82osLjFiYYq3TFHUdG4RgmN+C//EySxn/2PTu0RsJsdgBtXrp/OT3YGeesNgfzb1mFxq5Zhp0g==} - expo-symbols@57.0.2: - resolution: {integrity: sha512-qZ0iqOflm5lZGwRsQ5Y8sDksw3GAUKwHSX1bJBoocXf7gu14vafIXXYWte+JT9VfXAUGyKodJhLHP/GoOrcNWg==} + expo-symbols@58.0.3: + resolution: {integrity: sha512-WmO6gAjvUlgS3gFgvuHN/JRPsfHaDPiPj31i28YBN5yjg/B/k2UiPHFgqfktm8Tyy+rVtUr4ttMp91sibnybRw==} peerDependencies: expo: '*' expo-font: '*' react: '*' react-native: '*' - expo-updates-interface@57.0.1: - resolution: {integrity: sha512-+LUWwJ0gf/TEKMVdQAw/Gjih4dvrk+URgy24X9qEGKuuMDZqjBRm9T4yQyBVALGL5TTdPUaB6ILxx3lshm3pwQ==} + expo-updates-interface@58.0.1: + resolution: {integrity: sha512-OF+3BtMXtUsXWDfpHVNus9yHpx7WjMwjxDfeeN9LQBYSq/UtYmNNHBSfzChYTuqljWFSOAHRfsDykV9EB73Wlg==} peerDependencies: expo: '*' - expo-updates@57.0.19: - resolution: {integrity: sha512-xX4KIUa8H2xKmiVDe/uEehD96MV6nyyF/OCrE+PBYfOEp6BbS8bYkHZfNFcoDCKMRuT6pg9JrCi8OmnoWlM/2A==} + expo-updates@58.0.11: + resolution: {integrity: sha512-7mijq0yyFhPExPO/IS/feFrmrbR6pZP3WOAYf07RkfW/3lacLBxWt5/rKG9QMe7ydbvjqMednhca1Rx48lB2mg==} hasBin: true peerDependencies: expo: '*' @@ -7587,31 +7463,32 @@ packages: expo-dev-client: optional: true - expo-video@57.0.3: - resolution: {integrity: sha512-Z+rLdBSzICwoHm/HUxND5fm5nfgqiB+QPWAOKxmA8ScYwvxG1UGjZ6OaayvPc3GkT4aucsbycmFO0uUv/qnIhg==} + expo-video@58.0.5: + resolution: {integrity: sha512-iJM0z/HR7Gocywq5Z4ou1CvTMaoGrXVNb1HzzENpqF+endoJcOGZFgV5uq+OGbiLtm7S/LSm/CCtcPwvVsdcCw==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-web-browser@57.0.2: - resolution: {integrity: sha512-3vl5kvd7PB48ub6PpNIJUuPxO8xVa6D8RnIgNba6SXRwqFprOfeEZgwTgtm41kz0AAtvMOztUVNEUkwrHKjqMQ==} + expo-web-browser@58.0.3: + resolution: {integrity: sha512-SEPI0pphJ6rCTtJ01OWNRDTxvEqCTl3TkVRC3erUC1CGUrz5UWCzK+ejUx4F1WEayfj4j9tQAw0JDc+dzDq26g==} peerDependencies: expo: '*' react-native: '*' - expo-widgets@57.0.15: - resolution: {integrity: sha512-dlwbUCLaxOZFcIejxtOo95NyqJMa4Sop4NPzJEvvD2MwXERBqxkp8RExxVDAEiBRIdAYqC1u02SnIJWT/27f7g==} + expo-widgets@58.0.9: + resolution: {integrity: sha512-wGmI39qtJ6965rJA1bgAuKA2rEHfecoL939wxnBsSz3mvAAnSsjUNytP1rsVc0cBooPCssxqJST9EXGzee5Hfg==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo@57.0.18: - resolution: {integrity: sha512-6nax9hJPhf9dWrstliXUABTJXDNIJrfJKcCtjSxuYVs2Yf127GIhKf3wsEYSFUl+LFdRbPPTNaweJePH159wZA==} + expo@58.0.0: + resolution: {integrity: sha512-/KiC8tFY0hHl/mm49AFgNUFEQbnPthVh9o7EuDCSnTVpor8Cm/x1oqRyE97dxPT640lwuHO55xFO6OXopzjKXA==} + engines: {node: ^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0} hasBin: true peerDependencies: - '@expo/dom-webview': 57.0.1 + '@expo/dom-webview': 58.0.2 '@expo/metro-runtime': '*' react: '*' react-dom: '*' @@ -7755,12 +7632,25 @@ packages: flow-enums-runtime@0.0.6: resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + flow-estree@0.327.0: + resolution: {integrity: sha512-f9vK751YUzD0qaHSpKc5/qQM6gqOlgGS+4ZRqTNcZOpVqn3mC55yEQ6dUG2K1eaVm5FbKkz9CFWe6XNvrkQFQg==} + engines: {node: '>=18'} + + flow-estree@0.331.0: + resolution: {integrity: sha512-FVLYkSL/ITb/QXBEQvNWPjPooRGswuUtGOwrH+puSlMDneNkxy640+FZsk/TfKL+b7Wbw/Fg9FTUv2bMQDpj2w==} + engines: {node: '>=18'} + + flow-parser@0.327.0: + resolution: {integrity: sha512-/MYZ5hXWf5ozpbdfUDmazMgQXviLxWEiRLH3MppEGDdW0itRVqmB5UaU7QX+SBCDNiq+gEesSVn8nlxmPDyDkw==} + engines: {node: '>=0.4.0'} + + flow-parser@0.331.0: + resolution: {integrity: sha512-vEZcHIlnKeN8JSVtYFczj8sWJfHIJOkz+YG00O/oul/Bete+t1ZhTi+O6JRRLFYvGW+yJkZ0YgL16iStnbkUqQ==} + engines: {node: '>=0.4.0'} + fontace@0.4.1: resolution: {integrity: sha512-lDMvbAzSnHmbYMTEld5qdtvNH2/pWpICOqpean9IgC7vUbUJc3k+k5Dokp85CegamqQpFbXf0rAVkbzpyTA8aw==} - fontfaceobserver@2.3.0: - resolution: {integrity: sha512-6FPvD/IVyT4ZlNe7Wcn5Fb/4ChigpucKYSvD6a+0iMoLn2inpo711eyIcKjmDtE5XNcgAkSH9uN/nfAeZzHEfg==} - fontkitten@1.0.3: resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==} engines: {node: '>=20'} @@ -7840,10 +7730,6 @@ packages: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -7963,24 +7849,12 @@ packages: heic-to@1.5.2: resolution: {integrity: sha512-8Fns+lZHAWmz5U5IUxDeXKwIf3foBoKNPLxxFY4B0MkLjNuomEIHCoDbDE+x/llFK3NCEO1cu4+n3iUKY+Svmw==} - hermes-compiler@250829098.0.17: - resolution: {integrity: sha512-qG1PXzTEtriF6oQLZF3vyHhSMxOdW5h2TqqLri0rdpstPustd2fSvRZQMVAPdlhgFwBfYnj3OUZtiO6LjYsEFw==} - - hermes-estree@0.35.0: - resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} - - hermes-estree@0.36.0: - resolution: {integrity: sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==} + hermes-compiler@260318099.0.4: + resolution: {integrity: sha512-8odcPFkPC82HlqCl0C5QI9mBN4rEAT+IAo55sJhzwKw//K3qZloiv3ex6J2O8CuBbhdmkJozfidNsset2KH25w==} hermes-estree@0.36.1: resolution: {integrity: sha512-guv1nQ6IJ7S83NRFPWc3SA7IBZrdNC9kapwOq6uXvF4wP+sDCgjzQbKPCoyYmoyZRzztF/n/c36l/rccCZSiCw==} - hermes-parser@0.35.0: - resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} - - hermes-parser@0.36.0: - resolution: {integrity: sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==} - hermes-parser@0.36.1: resolution: {integrity: sha512-GApNk4zLHi2UWoWZZkx7LNCOSzLSc5lB55pZ/PhK7ycFeg7u5LcF88p/WbpIi1XUDtE0MpHE3uRR3u3KB7TjSQ==} @@ -7988,9 +7862,6 @@ packages: resolution: {integrity: sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==} hasBin: true - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - hono@4.13.7: resolution: {integrity: sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==} engines: {node: '>=16.9.0'} @@ -8057,11 +7928,6 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - image-size@1.2.1: - resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} - engines: {node: '>=16.x'} - hasBin: true - immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -8347,9 +8213,6 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lighthouse-logger@1.4.2: - resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} - lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -8517,9 +8380,6 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - marky@1.3.0: - resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - matcher@3.0.0: resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} engines: {node: '>=10'} @@ -8608,120 +8468,62 @@ packages: meshoptimizer@0.22.0: resolution: {integrity: sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==} - metro-babel-transformer@0.84.4: - resolution: {integrity: sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-babel-transformer@0.84.5: - resolution: {integrity: sha512-2WbHILKMiJUzfdjmGOQOqU1bWi9//gqiclc/tkk/AIsrrVw3efhZ1uhkOwMTxUEPOzqoo091H0olLmVZH5FHGQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-cache-key@0.84.4: - resolution: {integrity: sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-cache-key@0.84.5: - resolution: {integrity: sha512-3dPB2TnvGjjf0/9O7AXVQURKXuQNauTZE7WpTGTlR017Gh/B5y0m/2wcqxfveUguHSpu89KhVxCAlr2k/H7uhQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-cache@0.84.4: - resolution: {integrity: sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-babel-transformer@0.87.1: + resolution: {integrity: sha512-orvRIGpb0yK1yMbk5YP3dhVKjmoxUkRB9fdltGJxNppEqus/1tFpNuf9KnGFR3Qjg0izoUrJ4z6WgoBvdkXPrA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-cache@0.84.5: - resolution: {integrity: sha512-WHS0n2OxQqtwEjSeQFPePNrMvEFhmQcUQM9cRJMHByWoi/GMWFBEWOf7hVkAM/0KRutAXNbDlSu/cZB6CyxgQQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-cache-key@0.87.1: + resolution: {integrity: sha512-scqVVPMA2c+RVO12I3wyMDp5xCkRPLsyrcG4Qc3xfU5JR0EW/0sz2tjty+5UjMUtG09uiM1KYQ8HjWg7OQXHtw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-config@0.84.4: - resolution: {integrity: sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-cache@0.87.1: + resolution: {integrity: sha512-juNPaj0Xi5tkLp8imXqvbSnEIijwKG36m7OiFFVJMqEkiURwAjkMFVek3/xpix1+LVQqO7kjVp3PvuvIM61mKQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-config@0.84.5: - resolution: {integrity: sha512-zie+uN6oohscowi2S7ByU+wUw6CrT4ZxW9uAbONOObSxx86RGmnIAmjXHLkfmcdYoY7jzOPEbqcI6oeVmqyBQA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-config@0.87.1: + resolution: {integrity: sha512-NmkDlc/qZAdo5gTkVTuO2AKE/khemRKRH5IA+SKfqUBJigI5GqZ5TOXhmEokhlkAqzjt8dyzKhzI6FHvXoXaTQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-core@0.84.4: - resolution: {integrity: sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-core@0.87.1: + resolution: {integrity: sha512-xizzky/4+c/Mkznege8OW05j7bSdM39VPoEps61Se4+hf32UQujmbvLvIE9+UnP6kNEPVomk0Fw8NsBK9iRQmw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-core@0.84.5: - resolution: {integrity: sha512-xwm605hCi5Y6eJTTb8ZWo6pkUcoBEIyiQOfkZh5GwtDwUrP9SNhTQZhzJHrBCwwxlf3Ptl/pxWJgQ1rsNYMnrA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-file-map@0.87.1: + resolution: {integrity: sha512-9sPuNCojC3pS4vj+ZPY7FXmHGpdJeckXuKXQrDAfJvZc60AF8owRFTkI8XdwlwrmPIB2w++KraK9FMEXvC4wJw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-file-map@0.84.4: - resolution: {integrity: sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-minify-terser@0.87.1: + resolution: {integrity: sha512-YK4k1oO1wV48hfE+Nbw2rJCnAgeabzrgT/xH5ha5n9gbK4p3HYFC898cERUiyTl9vRh58CNTiXRc88f7y6PfKg==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-file-map@0.84.5: - resolution: {integrity: sha512-mlm/JL8toSbSc2akpKIGmzvrVRSCgZ5vkbycI34oMLoOnLGuLyC8WTyVJ6P0hZG/usDaGwZSl/s9BCRriqjGJA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-resolver@0.87.1: + resolution: {integrity: sha512-FXH/brY69wT6sPxaSW8BhMmDGD/6irmBr/cL4rUi+VWwqR3pbvdcfUOfyjcHucgQ7pe5IW3xJY21eHKLVKNumQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-minify-terser@0.84.4: - resolution: {integrity: sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-runtime@0.87.1: + resolution: {integrity: sha512-kjeuSvInsM6OzBjkCQsWxnkrKZFMKtnkCl38oXWRI9lDGs2L9hGs9Tak9sQYJ9h3gtDujneB7wZio+irgqJKDw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-minify-terser@0.84.5: - resolution: {integrity: sha512-BJoFwCEDsYnagPqarayInv2+diCDNDdLlaof/p6s9w4gh+gc9HXYM+pDvsKGKKUumpZswNF3Z/ftTMqKl/5IBg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-source-map@0.87.1: + resolution: {integrity: sha512-Bqpm0PBGdy53pigIJb4HRF7QxD2pUOdgSmVh/4AWbP635kSCv+Y6ltVxUZgSnzS/QbSmzyCGijmRPlXMj2/qHw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-resolver@0.84.4: - resolution: {integrity: sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-resolver@0.84.5: - resolution: {integrity: sha512-VSSnepg1k6LyCwtb6eirWdAWlpKwBG8Rdtsr1mU38rMelFyWgh3/QuMSiZIZAIjwg/fsa8GhW5/FO54CAUPCEA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-runtime@0.84.4: - resolution: {integrity: sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-runtime@0.84.5: - resolution: {integrity: sha512-U1m2+d1Pr+JO2/iVXBB2OfXXityz7tqwIorxfrT15IEgaHvpJBq/OHiqnOWPKJbUl3JcxjcdviZZOKk85oK4Qg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-source-map@0.84.4: - resolution: {integrity: sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-source-map@0.84.5: - resolution: {integrity: sha512-2BtV5L9uPc49F13Gn5wiP6bX/EncqzqTIk2VL/0F/96Vo0YEOjluT/qktQjFODfqGFsucwnh5mPEAl/2jVEfeg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-symbolicate@0.84.4: - resolution: {integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - - metro-symbolicate@0.84.5: - resolution: {integrity: sha512-rQ40zYDAkaWBN9yvjUuAD0ZpzBMZSoKyGYXnb5JrfbKjun7fTvfoLHL3KXFYenBTYZkQtlp4cKSCv/1utxFyOw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-symbolicate@0.87.1: + resolution: {integrity: sha512-rcGvwabrg0lbXGRGRKl14PY3My3+dkno2jZYhdJEuH2DmjTtTkV5bYwgto4JtV/Lbe+sXE6GO1UGg654430uow==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} hasBin: true - metro-transform-plugins@0.84.4: - resolution: {integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-transform-plugins@0.87.1: + resolution: {integrity: sha512-qMiJ/x+VfqumFJJSefKS6nj8uojzC29b2/aK8vlMuFABIqGjDucICEOXd2Yt6k/XMFAgAcaJvShUOT0HLyYaPw==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-transform-plugins@0.84.5: - resolution: {integrity: sha512-+InaSVGaOyt0DyRo4Y/zIdPI6CZwnbNho5LAL23tgmuGwv7fyfkF7kKfPjZcfxXBcoYdTLLFnCfCH/dHSiCqNg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro-transform-worker@0.87.1: + resolution: {integrity: sha512-VOzs3OV405FuOLYdAhqA2wsn1F9lvueDVxMDLvCKaQ44U+yknIqphJ9eMjjsGwLDZiJq9sW3DMLhjD27JxQgqQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} - metro-transform-worker@0.84.4: - resolution: {integrity: sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro-transform-worker@0.84.5: - resolution: {integrity: sha512-ui1Z8x4s5RL36gMmKLaMMO7O9NNDHNdthEZSCDQHAau3JcAsTaFOK6I+2q4I/kW5u8hSEjJk9L45TXSVJw6g1A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - metro@0.84.4: - resolution: {integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true - - metro@0.84.5: - resolution: {integrity: sha512-r1liLkyFZMVSEMNjU1CJU5pRzs3NdkxHqXS60O25c0rCIqAR+cGk7rPydw/g0WAIKVXojIBIF45yYBPagJGcgw==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + metro@0.87.1: + resolution: {integrity: sha512-1oyLU9elM7hPAsKIqKooEekwxiuWr27+MZBhUROPhzcbXhMDxK64GPF/hCXwBZVp1F89ODavCrBmJtLx9WtBoQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} hasBin: true micromark-core-commonmark@2.0.3: @@ -8900,11 +8702,6 @@ packages: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - modern-tar@0.8.5: resolution: {integrity: sha512-snEhs+6G5Tjd4I7tLCDOaoln2RgE0bD19RzEKgvgK2hZ5VKy3MpLhLTZ2fWpXSTg4K2cyPwp+VHATFJhxfnOeA==} engines: {node: '>=18.0.0'} @@ -9061,6 +8858,10 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} + noxcturnal@0.1.1: + resolution: {integrity: sha512-Fa9SvpVNi+2AVr9CI6mkxqIIeGQNlVRLZsXdinOx1xrvV5ZvCsyBff9QRJdwnzlVnn1AIpksFe9SW9sDfzYKLw==} + engines: {node: '>=18'} + npm-package-arg@11.0.3: resolution: {integrity: sha512-sHGJy8sOC1YraBywpzQlIKBE4pBbGbiF95U6Auspzyem956E0+FtDtsx1ZxlOJkQCZ1AFXAY/yuvtFYrOxF+Bw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -9087,13 +8888,9 @@ packages: oas-validator@5.0.8: resolution: {integrity: sha512-cu20/HE5N5HKqVygs3dt94eYJfBi0TsZvPVXDhbXQHiEityDN+RROTleefoKRKKJ9dFAF2JBkDHgvWj0sjKGmw==} - ob1@0.84.4: - resolution: {integrity: sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - - ob1@0.84.5: - resolution: {integrity: sha512-aH9RkoZc7w/90HBamFxTw8ZLFr05wXS+iOnvmrgo53Ep8Pyrm5FieQSaPIVROkfFVQISeD/zo92fes26TOwe+A==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + ob1@0.87.1: + resolution: {integrity: sha512-i8iA8uij0g1YQzS8uOJPSRCgwDjO9warIHUAu1Fqj877Wc3wlfxDYBioYWgKTBF2+URVJttyDWSEpmd99nlvtQ==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} @@ -9150,9 +8947,9 @@ packages: oniguruma-to-es@4.3.6: resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} - open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} ora@3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} @@ -9558,9 +9355,6 @@ packages: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} - queue@6.0.2: - resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} - quick-lru@5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} @@ -9589,16 +9383,16 @@ packages: react-devtools-core@6.1.5: resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} - peerDependencies: - react: ^19.2.3 - react-dom@19.2.6: resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: react: ^19.2.6 + react-dom@19.3.0: + resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} + peerDependencies: + react: ^19.3.0 + react-freeze@1.0.4: resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} engines: {node: '>=10'} @@ -9614,9 +9408,6 @@ packages: react: optional: true - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} @@ -9632,8 +9423,8 @@ packages: '@types/react': '>=18' react: '>=18' - react-native-gesture-handler@2.32.0: - resolution: {integrity: sha512-uYIMOKlKENORq2SABE+jIjbPU+h5I/sQKcq2v16zRq848nwEp1fWRVwML4QWqijc8UcXJC25o54S8GQd4Mf2OA==} + react-native-gesture-handler@3.2.1: + resolution: {integrity: sha512-VEWscxUN29aeccbD2McF0LSXrwOhSdisaSRFiEWg0O/3WrVghNJp/tOtLrCgzb9gfcZ3xdA+K2Sp8F5G3iHx/Q==} peerDependencies: react: '*' react-native: '*' @@ -9650,8 +9441,8 @@ packages: react: '*' react-native: '*' - react-native-keyboard-controller@1.21.13: - resolution: {integrity: sha512-FLr0MucraPyCGykRAcPM8Bv0JT5TcG1juQGMI+GLDuuaoOUKUY3SMUnRhHn7IgSM8KlxpcNQmMPNDmGpOw1OcA==} + react-native-keyboard-controller@1.22.4: + resolution: {integrity: sha512-2by3oJBQqKH9UAydlBeiEpivxIyTbt345bmverLym7vbEp4NXckWQLF0STnVuXYccRak5/sd3wMYDJPhv/9+3g==} peerDependencies: react: '*' react-native: '*' @@ -9677,21 +9468,21 @@ packages: react: '*' react-native: '*' - react-native-reanimated@4.5.5: - resolution: {integrity: sha512-xtJXZRZ1vkec1AIUVG02St2sbyZS5jc7227TlDu/HonqUYPeZAfiC4RI2jqL1dVMNBu1+7oBx/c9QkjF2kg6Lg==} + react-native-reanimated@4.7.0: + resolution: {integrity: sha512-8TyTrPisqz7WzmbhCz8F60Uw7NI2QeYWrY5Hk58/kurCA5L5KuHmhyQjxeq5k2YalpXUAKbdkn/mAMZWm/fU0g==} peerDependencies: react: '*' - react-native: 0.83 - 0.86 - react-native-worklets: 0.10.x - 0.11.x + react-native: 0.86 - 0.88 + react-native-worklets: 0.13.x - react-native-safe-area-context@5.7.0: - resolution: {integrity: sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ==} + react-native-safe-area-context@5.9.1: + resolution: {integrity: sha512-Zpx9Iwg6VhgNarWFpcIM61xK2lUbSfSXemQUmcvOVRpux49lJsUompY1S3E5jKUJbLq233qEpj28DgmXVsgZMQ==} peerDependencies: react: '*' react-native: '*' - react-native-screens@4.26.2: - resolution: {integrity: sha512-2XnWsZToKj76trGtEZzx5ELD/qOICFEprEeUntImmitQFVUkea27fiWdUSITArI356Y1qynpXZINW+Unbhky/A==} + react-native-screens@4.28.0: + resolution: {integrity: sha512-0/79Z8RCibuaAHti+DJ2Dq0m6UFWh4+p1bH58K3cjiQ7IDWs5kU9tCAj4lXcJMHHonbF2mIE2BeaPSEvOpIiFg==} peerDependencies: react: '*' react-native: '*' @@ -9702,8 +9493,8 @@ packages: react: '*' react-native: '*' - react-native-svg@15.15.4: - resolution: {integrity: sha512-boT/vIRgj6zZKBpfTPJJiYWMbZE9duBMOwPK6kCSTgxsS947IFMOq9OgIFkpWZTB7t229H24pDRkh3W9ZK/J1A==} + react-native-svg@15.15.5: + resolution: {integrity: sha512-L4go5jA+GWutdJ/JucuN20cjAbMg1HmMtAP+wZ+3JLCf6Jd0bhXQHxciRP/AQm/FlrIEZwkMcHNZP+FXAiic0w==} peerDependencies: react: '*' react-native: '*' @@ -9713,39 +9504,28 @@ packages: peerDependencies: react-native: '*' - react-native-webview@13.16.1: - resolution: {integrity: sha512-If0eHhoEdOYDcHsX+xBFwHMbWBGK1BvGDQDQdVkwtSIXiq1uiqjkpWVP2uQ1as94J0CzvFE9PUNDuhiX0Z6ubw==} + react-native-webview@14.0.1: + resolution: {integrity: sha512-lBUuvFk459Mo+5vUNqwzGvn+I8rDJE6zvOulG2hWWudeEOJfWTsQwOfuYnRu+27djUIXrESFfC+EQE3PGu+FWA==} peerDependencies: react: '*' react-native: '*' - react-native-worklets@0.10.1: - resolution: {integrity: sha512-62mRM19bDpfpdI8HLkEErcdOsrAPDtE9lA/sw+5lLRpzBHNhxaoj9QyY2KjXqUmirelxkX4zuPGTC3VdA0feJA==} - peerDependencies: - '@babel/core': '*' - '@react-native/metro-config': '*' - react: '*' - react-native: 0.83 - 0.86 - - react-native-worklets@0.11.4: - resolution: {integrity: sha512-yNiDDQAVvt1wacBhnrEMTBlQzZ8Y8Rg7Dbdxs/r595EXw4REsZGE5sY1Ug8SmlQUT+0L+fX7oY0SuCs0mjiA4w==} + react-native-worklets@0.13.0: + resolution: {integrity: sha512-1OrhAeAKaZF4XrBa4YbPQbKzNOpjh52HDlId8e6ete1OCHNdAlrQHzG4gznJ225EAj3dgQXHViJvK51M9B52jQ==} peerDependencies: '@babel/core': '*' '@react-native/metro-config': '*' react: '*' - react-native: 0.83 - 0.86 + react-native: 0.86 - 0.88 - react-native@0.86.3: - resolution: {integrity: sha512-JR5s3bM9ezud+Mw24GlNXNfthqPIKwrQgPPJcam+L97t2sKjjEavhCzBn+fyqZZRcM5+XlhYxpTxVkK7e1n38Q==} - engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + react-native@0.88.0-rc.3: + resolution: {integrity: sha512-8gTeprAQP1j3B8lUJGZNmo33jH41Hmrd1Jm9PoOr7D/uImnifPqkagpFSKyK9fPJTWtwAK2TLDqTo+eFxlUcvA==} + engines: {node: ^22.13.0 || ^24.3.0 || >= 26.0.0} hasBin: true peerDependencies: - '@react-native/jest-preset': 0.86.3 '@types/react': ^19.1.1 - react: ^19.2.3 + react: ^19.3.0 peerDependenciesMeta: - '@react-native/jest-preset': - optional: true '@types/react': optional: true @@ -9753,49 +9533,19 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - react-test-renderer@19.2.6: resolution: {integrity: sha512-GbS6V23YduFTPiWJ5xICbKEjRcqx1Z90js/V5miqhz7qp/d6xSe9Dd6NjSQODFRdzdsqRMPW82E/sFpPRbY5Mw==} peerDependencies: react: ^19.2.6 - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} - engines: {node: '>=0.10.0'} - react@19.2.6: resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} engines: {node: '>=0.10.0'} + react@19.3.0: + resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==} + engines: {node: '>=0.10.0'} + read-binary-file-arch@1.0.6: resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} hasBin: true @@ -9994,6 +9744,9 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} + schema-utils@4.3.3: resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} engines: {node: '>= 10.13.0'} @@ -10615,7 +10368,7 @@ packages: resolution: {integrity: sha512-e2mYlHrZzAQtZUf3STrfVDTetspv7p5vm/cu6p8kjLRQaL9r6QFG+MlwZ3hrI2LHnzgzjbSo+MwvoE380zz2JQ==} hasBin: true peerDependencies: - '@expo/metro-config': 57.0.12 + '@expo/metro-config': 58.0.6 metro: '*' metro-cache: '*' metro-transform-worker: '*' @@ -10723,31 +10476,11 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - use-latest-callback@0.2.6: resolution: {integrity: sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg==} peerDependencies: react: '>=16.8' - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - use-sync-external-store@1.6.0: resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} peerDependencies: @@ -10788,12 +10521,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vaul@1.1.2: - resolution: {integrity: sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA==} - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - vfile-location@5.0.3: resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} @@ -11007,8 +10734,8 @@ packages: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} - whatwg-url-minimum@0.1.2: - resolution: {integrity: sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==} + whatwg-url-minimum@0.2.0: + resolution: {integrity: sha512-BtjXU1caNcCFfETP2DhqSeVPfRDl2MTUitI107RE34rJXjR/izfUtR5IoTFOK1WqjNLXbbeqaCH/mQAOLjpc8g==} whatwg-url@14.2.0: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} @@ -11241,6 +10968,10 @@ packages: snapshots: + 2g@0.4.4(typescript@7.0.2): + optionalDependencies: + typescript: 7.0.2 + '@ai-sdk/provider-utils@4.0.49(zod@4.4.3)': dependencies: '@ai-sdk/provider': 3.0.15 @@ -11285,9 +11016,9 @@ snapshots: chokidar: 5.0.0 rolldown: 1.2.5 - '@alchemy.run/sigil@0.0.0-alpha.11(@types/react@19.2.16)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))': + '@alchemy.run/sigil@0.0.0-alpha.11(@types/react@19.3.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))': optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 react-devtools-core: 6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) '@anthropic-ai/claude-agent-sdk@0.3.276(@anthropic-ai/sdk@0.93.0(zod@4.6.5))(@modelcontextprotocol/sdk@1.29.0(zod@4.6.5))(zod@4.6.5)': @@ -11745,7 +11476,7 @@ snapshots: '@babel/helper-module-imports@7.29.7': dependencies: '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -11810,7 +11541,7 @@ snapshots: '@babel/parser@7.29.7': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@babel/parser@7.29.8': dependencies: @@ -12045,17 +11776,6 @@ snapshots: '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.29.7)': - dependencies: - '@babel/core': 7.29.7 - '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-module-imports': 7.29.7 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-react-jsx@7.29.7(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 @@ -12063,7 +11783,7 @@ snapshots: '@babel/helper-module-imports': 7.29.7 '@babel/helper-plugin-utils': 7.29.7 '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -12158,10 +11878,10 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 - '@base-ui/react@1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.16)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@base-ui/react@1.5.0(@date-fns/tz@1.5.0)(@types/react@19.3.0)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@babel/runtime': 7.29.7 - '@base-ui/utils': 0.2.9(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@base-ui/utils': 0.2.9(@types/react@19.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@floating-ui/utils': 0.2.11 react: 19.2.6 @@ -12169,10 +11889,10 @@ snapshots: use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: '@date-fns/tz': 1.5.0 - '@types/react': 19.2.16 + '@types/react': 19.3.0 date-fns: 4.4.0 - '@base-ui/utils@0.2.9(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@base-ui/utils@0.2.9(@types/react@19.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@babel/runtime': 7.29.7 '@floating-ui/utils': 0.2.11 @@ -12181,7 +11901,7 @@ snapshots: reselect: 5.2.0 use-sync-external-store: 1.6.0(react@19.2.6) optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 '@blazediff/core@1.10.0': {} @@ -12236,18 +11956,18 @@ snapshots: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 - '@clerk/backend@3.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@clerk/backend@3.18.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6)': dependencies: - '@clerk/shared': 4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.2.6) standardwebhooks: 1.0.0 tslib: 2.8.1 transitivePeerDependencies: - react - react-dom - '@clerk/clerk-js@6.32.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@clerk/clerk-js@6.32.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@clerk/shared': 4.33.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@clerk/shared': 4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@stripe/stripe-js': 5.6.0 '@swc/helpers': 0.5.21 '@tanstack/query-core': 5.102.8 @@ -12262,9 +11982,26 @@ snapshots: - react - react-dom - '@clerk/clerk-js@6.32.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@clerk/clerk-js@6.32.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6)': dependencies: - '@clerk/shared': 4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.2.6) + '@stripe/stripe-js': 5.6.0 + '@swc/helpers': 0.5.21 + '@tanstack/query-core': 5.102.8 + '@zxcvbn-ts/core': 3.0.4 + '@zxcvbn-ts/language-common': 3.0.4 + alien-signals: 2.0.6 + browser-tabs-lock: 1.3.0 + core-js: 3.47.0 + crypto-js: 4.2.0 + dequal: 2.0.3 + transitivePeerDependencies: + - react + - react-dom + + '@clerk/clerk-js@6.32.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@stripe/stripe-js': 5.6.0 '@swc/helpers': 0.5.21 '@tanstack/query-core': 5.102.8 @@ -12311,36 +12048,42 @@ snapshots: electron-store: 8.2.0 react-dom: 19.2.6(react@19.2.6) - '@clerk/expo@4.6.8(patch_hash=a82bb41039ee88a290a87d4ab58be7be4c49fa338603b17ea646e1ec140a1cfb)(dbc31631339ce74330e188d5d7a88158)': + '@clerk/electron@0.0.44(@clerk/electron-passkeys@0.0.3)(electron-store@8.2.0)(electron@44.4.2)(react-dom@19.3.0(react@19.3.0))(react@19.2.6)': + dependencies: + '@clerk/clerk-js': 6.32.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6) + '@clerk/react': 6.16.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6) + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.2.6) + electron: 44.4.2 + react: 19.2.6 + tslib: 2.8.1 + optionalDependencies: + '@clerk/electron-passkeys': 0.0.3 + electron-store: 8.2.0 + react-dom: 19.3.0(react@19.3.0) + + '@clerk/expo@4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(950bb7335d61b76ffb649f136fc0d4df)': dependencies: - '@clerk/clerk-js': 6.32.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@clerk/react': 6.16.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@clerk/shared': 4.33.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) + '@clerk/clerk-js': 6.32.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@clerk/react': 6.16.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) base-64: 1.0.0 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-url-polyfill: 4.0.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-url-polyfill: 4.0.0(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) tslib: 2.8.1 optionalDependencies: - expo-auth-session: 57.0.10(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-crypto: 57.0.2(expo@57.0.18) - expo-secure-store: 57.0.2(expo@57.0.18) - expo-web-browser: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - react-dom: 19.2.3(react@19.2.3) + expo-auth-session: 58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-crypto: 58.0.3(expo@58.0.0) + expo-secure-store: 58.0.1(expo@58.0.0) + expo-web-browser: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - supports-color - typescript - '@clerk/react@6.16.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@clerk/shared': 4.33.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tslib: 2.8.1 - '@clerk/react@6.16.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@clerk/shared': 4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -12348,17 +12091,31 @@ snapshots: react-dom: 19.2.6(react@19.2.6) tslib: 2.8.1 - '@clerk/shared@4.33.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@clerk/react@6.16.1(react-dom@19.3.0(react@19.3.0))(react@19.2.6)': + dependencies: + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.2.6) + react: 19.2.6 + react-dom: 19.3.0(react@19.3.0) + tslib: 2.8.1 + + '@clerk/react@6.16.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + tslib: 2.8.1 + + '@clerk/shared@4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@tanstack/query-core': 5.102.8 dequal: 2.0.3 glob-to-regexp: 0.4.1 js-cookie: 3.0.8 optionalDependencies: - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@clerk/shared@4.33.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@clerk/shared@4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.2.6)': dependencies: '@tanstack/query-core': 5.102.8 dequal: 2.0.3 @@ -12366,7 +12123,17 @@ snapshots: js-cookie: 3.0.8 optionalDependencies: react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + react-dom: 19.3.0(react@19.3.0) + + '@clerk/shared@4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@tanstack/query-core': 5.102.8 + dequal: 2.0.3 + glob-to-regexp: 0.4.1 + js-cookie: 3.0.8 + optionalDependencies: + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260901.1)': dependencies: @@ -12446,12 +12213,12 @@ snapshots: '@date-fns/tz@1.5.0': {} - '@daypicker/react@10.0.1(@types/react@19.2.16)(react@19.2.6)': + '@daypicker/react@10.0.1(@types/react@19.3.0)(react@19.2.6)': dependencies: react: 19.2.6 - react-day-picker: 10.0.1(@types/react@19.2.16)(react@19.2.6) + react-day-picker: 10.0.1(@types/react@19.3.0)(react@19.2.6) optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 '@dimforge/rapier3d-compat@0.12.0': {} @@ -12549,16 +12316,16 @@ snapshots: '@drizzle-team/brocli@0.12.0': {} - '@effect/atom-react@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.2.3)(scheduler@0.27.0)': + '@effect/atom-react@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.2.6)(scheduler@0.27.0)': dependencies: effect: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) - react: 19.2.3 + react: 19.2.6 scheduler: 0.27.0 - '@effect/atom-react@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.2.6)(scheduler@0.27.0)': + '@effect/atom-react@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.3.0)(scheduler@0.27.0)': dependencies: effect: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) - react: 19.2.6 + react: 19.3.0 scheduler: 0.27.0 '@effect/openapi-generator@4.0.0-rc.115(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(encoding@0.1.13)': @@ -12641,10 +12408,6 @@ snapshots: dependencies: effect: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) - '@egjs/hammerjs@2.0.17': - dependencies: - '@types/hammerjs': 2.0.46 - '@electric-sql/pglite@0.3.15': optional: true @@ -12999,110 +12762,36 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.38': {} - '@expo/cli@57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(bufferutil@4.1.0)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2)(utf-8-validate@6.0.6)': - dependencies: - '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/devcert': 1.2.1 - '@expo/env': 2.4.3 - '@expo/image-utils': 0.11.5(typescript@7.0.2) - '@expo/inline-modules': 0.1.7(typescript@7.0.2) - '@expo/json-file': 11.0.1 - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - '@expo/metro': 56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6) - '@expo/metro-file-map': 57.0.2 - '@expo/osascript': 2.7.1 - '@expo/package-manager': 1.13.1 - '@expo/plist': 0.8.1 - '@expo/prebuild-config': 57.0.15(typescript@7.0.2) - '@expo/require-utils': 57.0.5(typescript@7.0.2) - '@expo/router-server': 57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@expo/schema-utils': 57.0.2 - '@expo/spawn-async': 1.8.0 - '@expo/ws-tunnel': 2.0.0(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) - '@expo/xcpretty': 4.4.4 - '@react-native/dev-middleware': 0.86.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) - accepts: 1.3.8 - agent-cli-detector: 0.1.6 - arg: 5.0.2 - bplist-creator: 0.1.0 - bplist-parser: 0.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - compression: 1.8.1 - connect: 3.7.0 - debug: 4.4.3 - dnssd-advertise: 1.1.4 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-server: 57.0.3 - fetch-nodeshim: 0.4.10 - getenv: 2.0.0 - glob: 13.0.6 - lan-network: 0.2.1 - multitars: 1.0.2 - node-forge: 1.4.0 - npm-package-arg: 11.0.3 - ora: 3.4.0 - picomatch: 4.0.7 - pretty-format: 29.7.0 - progress: 2.0.3 - prompts: 2.4.2 - resolve-from: 5.0.0 - sandbox-cli-detector: 0.2.0 - semver: 7.8.5 - send: 0.19.2 - slugify: 1.6.9 - stacktrace-parser: 0.1.11 - structured-headers: 0.4.1 - terminal-link: 2.1.1 - toqr: 0.1.1 - wrap-ansi: 7.0.0 - ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) - zod: 3.25.76 - optionalDependencies: - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - transitivePeerDependencies: - - '@expo/dom-webview' - - '@expo/metro-runtime' - - bufferutil - - expo-constants - - expo-font - - react - - react-dom - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate - - '@expo/cli@57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(bufferutil@4.1.0)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)(typescript@7.0.2)(utf-8-validate@6.0.6)': + '@expo/cli@58.0.9(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.9)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6)': dependencies: + 2g: 0.4.4(typescript@7.0.2) '@expo/code-signing-certificates': 0.0.6 - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) + '@expo/config': 58.0.1(typescript@7.0.2) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) '@expo/devcert': 1.2.1 - '@expo/env': 2.4.3 - '@expo/image-utils': 0.11.5(typescript@7.0.2) - '@expo/inline-modules': 0.1.7(typescript@7.0.2) - '@expo/json-file': 11.0.1 - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - '@expo/metro': 56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6) - '@expo/metro-file-map': 57.0.2 - '@expo/osascript': 2.7.1 - '@expo/package-manager': 1.13.1 - '@expo/plist': 0.8.1 - '@expo/prebuild-config': 57.0.15(typescript@7.0.2) - '@expo/require-utils': 57.0.5(typescript@7.0.2) - '@expo/router-server': 57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@expo/schema-utils': 57.0.2 + '@expo/env': 2.5.1 + '@expo/image-utils': 0.12.2(typescript@7.0.2) + '@expo/inline-modules': 0.2.1(typescript@7.0.2) + '@expo/json-file': 11.2.1 + '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box-utils': 58.0.1 + '@expo/metro': 58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/metro-file-map': 58.0.3(typescript@7.0.2) + '@expo/osascript': 2.8.1 + '@expo/package-manager': 1.14.1 + '@expo/plist': 0.10.1 + '@expo/prebuild-config': 58.0.6(typescript@7.0.2) + '@expo/require-utils': 58.0.2(typescript@7.0.2) + '@expo/router-server': 58.0.4(@expo/metro-runtime@58.0.9)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@expo/schema-utils': 58.0.1 '@expo/spawn-async': 1.8.0 '@expo/ws-tunnel': 2.0.0(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) '@expo/xcpretty': 4.4.4 - '@react-native/dev-middleware': 0.86.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@react-native/dev-middleware': 0.88.0-rc.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@react-native/js-polyfills': 0.88.0-rc.3 accepts: 1.3.8 - agent-cli-detector: 0.1.6 + agent-cli-detector: 0.1.7 arg: 5.0.2 bplist-creator: 0.1.0 bplist-parser: 0.3.2 @@ -13110,10 +12799,9 @@ snapshots: ci-info: 3.9.0 compression: 1.8.1 connect: 3.7.0 - debug: 4.4.3 - dnssd-advertise: 1.1.4 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - expo-server: 57.0.3 + dnssd-advertise: 1.1.6 + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-server: 58.0.2 fetch-nodeshim: 0.4.10 getenv: 2.0.0 glob: 13.0.6 @@ -13139,7 +12827,7 @@ snapshots: ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) zod: 3.25.76 optionalDependencies: - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - '@expo/dom-webview' - '@expo/metro-runtime' @@ -13152,18 +12840,17 @@ snapshots: - supports-color - typescript - utf-8-validate - optional: true '@expo/code-signing-certificates@0.0.6': dependencies: node-forge: 1.4.0 - '@expo/config-plugins@57.0.9(typescript@7.0.2)': + '@expo/config-plugins@58.0.4(typescript@7.0.2)': dependencies: - '@expo/config-types': 57.0.2 - '@expo/json-file': 11.0.1 - '@expo/plist': 0.8.1 - '@expo/require-utils': 57.0.5(typescript@7.0.2) + '@expo/config-types': 58.0.2 + '@expo/json-file': 11.2.1 + '@expo/plist': 0.10.1 + '@expo/require-utils': 58.0.2(typescript@7.0.2) '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 debug: 4.4.3 @@ -13177,14 +12864,14 @@ snapshots: - supports-color - typescript - '@expo/config-types@57.0.2': {} + '@expo/config-types@58.0.2': {} - '@expo/config@57.0.9(typescript@7.0.2)': + '@expo/config@58.0.1(typescript@7.0.2)': dependencies: - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/config-types': 57.0.2 - '@expo/json-file': 11.0.1 - '@expo/require-utils': 57.0.5(typescript@7.0.2) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) + '@expo/config-types': 58.0.2 + '@expo/json-file': 11.2.1 + '@expo/require-utils': 58.0.2(typescript@7.0.2) deepmerge: 4.3.1 getenv: 2.0.0 glob: 13.0.6 @@ -13202,35 +12889,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/devtools@57.0.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@expo/devtools@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: chalk: 4.1.2 optionalDependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - - '@expo/devtools@57.0.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)': - dependencies: - chalk: 4.1.2 - optionalDependencies: - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true - - '@expo/dom-webview@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': - dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - '@expo/dom-webview@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)': + '@expo/dom-webview@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - '@expo/env@2.4.3': + '@expo/env@2.5.1': dependencies: chalk: 4.1.2 debug: 4.4.3 @@ -13238,11 +12911,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/expo-modules-macros-plugin@0.6.1': {} - - '@expo/fingerprint@0.20.11': + '@expo/fingerprint@0.21.2': dependencies: - '@expo/env': 2.4.3 + '@expo/env': 2.5.1 '@expo/spawn-async': 1.8.0 arg: 5.0.2 chalk: 4.1.2 @@ -13256,9 +12927,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/image-utils@0.11.5(typescript@7.0.2)': + '@expo/image-utils@0.12.2(typescript@7.0.2)': dependencies: - '@expo/require-utils': 57.0.5(typescript@7.0.2) + '@expo/require-utils': 58.0.2(typescript@7.0.2) '@expo/spawn-async': 1.8.0 chalk: 4.1.2 getenv: 2.0.0 @@ -13282,59 +12953,56 @@ snapshots: - supports-color - typescript - '@expo/inline-modules@0.1.7(typescript@7.0.2)': + '@expo/inline-modules@0.2.1(typescript@7.0.2)': dependencies: - '@expo/config-plugins': 57.0.9(typescript@7.0.2) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) transitivePeerDependencies: - supports-color - typescript - '@expo/json-file@11.0.1': + '@expo/json-file@11.2.1': dependencies: '@babel/code-frame': 7.29.7 json5: 2.2.3 - '@expo/local-build-cache-provider@57.0.8(typescript@7.0.2)': + '@expo/local-build-cache-provider@58.0.1(typescript@7.0.2)': dependencies: - '@expo/config': 57.0.9(typescript@7.0.2) + '@expo/config': 58.0.1(typescript@7.0.2) chalk: 4.1.2 transitivePeerDependencies: - supports-color - typescript - '@expo/log-box@57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': - dependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - anser: 1.4.10 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - stacktrace-parser: 0.1.11 + '@expo/log-box-utils@58.0.1': {} - '@expo/log-box@57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)': + '@expo/log-box@58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) + '@expo/dom-webview': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box-utils': 58.0.1 anser: 1.4.10 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) stacktrace-parser: 0.1.11 - optional: true + optionalDependencies: + expo: 58.0.0(3abfa3879936d948a635873738556226) - '@expo/metro-config@57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6)': + '@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6)': dependencies: + 2g: 0.4.4(typescript@7.0.2) '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 '@babel/generator': 7.29.7 - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/env': 2.4.3 - '@expo/json-file': 11.0.1 - '@expo/metro': 56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/require-utils': 57.0.5(typescript@7.0.2) + '@expo/config': 58.0.1(typescript@7.0.2) + '@expo/env': 2.5.1 + '@expo/json-file': 11.2.1 + '@expo/metro': 58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@expo/require-utils': 58.0.2(typescript@7.0.2) '@expo/spawn-async': 1.8.0 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.6.0 + '@jridgewell/trace-mapping': 0.3.31 + '@react-native/js-polyfills': 0.88.0-rc.3 browserslist: 4.29.0 chalk: 4.1.2 debug: 4.4.3 @@ -13343,19 +13011,21 @@ snapshots: hermes-parser: 0.36.1 jsc-safe-url: 0.2.4 lightningcss: 1.33.0 + noxcturnal: 0.1.1 picomatch: 4.0.7 postcss: 8.5.28 resolve-from: 5.0.0 optionalDependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) transitivePeerDependencies: - bufferutil - supports-color - typescript - utf-8-validate - '@expo/metro-file-map@57.0.2': + '@expo/metro-file-map@58.0.3(typescript@7.0.2)': dependencies: + 2g: 0.4.4(typescript@7.0.2) debug: 4.4.3 fb-watchman: 2.0.2 invariant: 2.2.4 @@ -13364,85 +13034,71 @@ snapshots: walker: 1.0.8 transitivePeerDependencies: - supports-color + - typescript - '@expo/metro-runtime@57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': - dependencies: - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - anser: 1.4.10 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - pretty-format: 29.7.0 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - stacktrace-parser: 0.1.11 - whatwg-fetch: 3.6.20 - optionalDependencies: - react-dom: 19.2.3(react@19.2.3) - optional: true - - '@expo/metro-runtime@57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)': + '@expo/metro-runtime@58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) + '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) anser: 1.4.10 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) + expo: 58.0.0(3abfa3879936d948a635873738556226) pretty-format: 29.7.0 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) stacktrace-parser: 0.1.11 whatwg-fetch: 3.6.20 optionalDependencies: - react-dom: 19.2.6(react@19.2.6) - optional: true - - '@expo/metro@56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6)': - dependencies: - metro: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-babel-transformer: 0.84.5 - metro-cache: 0.84.5 - metro-cache-key: 0.84.5 - metro-config: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) + react-dom: 19.3.0(react@19.3.0) + + '@expo/metro@58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + dependencies: + metro: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + metro-babel-transformer: 0.87.1 + metro-cache: 0.87.1 + metro-cache-key: 0.87.1 + metro-config: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@expo/osascript@2.7.1': + '@expo/osascript@2.8.1': dependencies: '@expo/spawn-async': 1.8.0 - '@expo/package-manager@1.13.1': + '@expo/package-manager@1.14.1': dependencies: - '@expo/json-file': 11.0.1 + '@expo/json-file': 11.2.1 '@expo/spawn-async': 1.8.0 chalk: 4.1.2 npm-package-arg: 11.0.3 ora: 3.4.0 resolve-workspace-root: 2.0.1 - '@expo/plist@0.8.1': + '@expo/plist@0.10.1': dependencies: '@xmldom/xmldom': 0.8.15 base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@57.0.15(typescript@7.0.2)': + '@expo/prebuild-config@58.0.6(typescript@7.0.2)': dependencies: - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/config-types': 57.0.2 - '@expo/image-utils': 0.11.5(typescript@7.0.2) - '@expo/json-file': 11.0.1 - '@react-native/normalize-colors': 0.86.3 + '@expo/config': 58.0.1(typescript@7.0.2) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) + '@expo/config-types': 58.0.2 + '@expo/image-utils': 0.12.2(typescript@7.0.2) + '@expo/json-file': 11.2.1 + '@react-native/normalize-colors': 0.88.0-rc.3 debug: 4.4.3 - expo-modules-autolinking: 57.0.12(typescript@7.0.2) + expo-modules-autolinking: 58.0.6(typescript@7.0.2) resolve-from: 5.0.0 semver: 7.8.5 transitivePeerDependencies: @@ -13459,7 +13115,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/require-utils@57.0.5(typescript@7.0.2)': + '@expo/require-utils@58.0.2(typescript@7.0.2)': dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 @@ -13469,36 +13125,21 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - debug: 4.4.3 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo-server: 57.0.3 - react: 19.2.3 - optionalDependencies: - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react-dom: 19.2.3(react@19.2.3) - transitivePeerDependencies: - - supports-color - - '@expo/router-server@57.0.8(@expo/metro-runtime@57.0.14)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(expo-server@57.0.3)(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@expo/router-server@58.0.4(@expo/metro-runtime@58.0.9)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: debug: 4.4.3 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)) - expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - expo-server: 57.0.3 - react: 19.2.6 + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-server: 58.0.2 + react: 19.3.0 optionalDependencies: - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - react-dom: 19.2.6(react@19.2.6) + '@expo/metro-runtime': 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - supports-color - optional: true - '@expo/schema-utils@57.0.2': {} + '@expo/schema-utils@58.0.1': {} '@expo/sdk-runtime-versions@1.0.0': {} @@ -13508,20 +13149,16 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/ui@57.0.14(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@expo/ui@58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 - vaul: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) optionalDependencies: '@babel/core': 7.29.7 - react-dom: 19.2.3(react@19.2.3) - react-native-worklets: 0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' + react-dom: 19.3.0(react@19.3.0) + react-native-worklets: 0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/ws-tunnel@2.0.0(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6))': dependencies: @@ -13784,14 +13421,6 @@ snapshots: dependencies: jsbi: 4.3.2 - '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': - dependencies: - react: 19.2.3 - use-sync-external-store: 1.6.0(react@19.2.3) - optionalDependencies: - react-dom: 19.2.3(react@19.2.3) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: react: 19.2.6 @@ -13799,6 +13428,14 @@ snapshots: optionalDependencies: react-dom: 19.2.6(react@19.2.6) + '@legendapp/list@3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + dependencies: + react: 19.3.0 + use-sync-external-store: 1.6.0(react@19.3.0) + optionalDependencies: + react-dom: 19.3.0(react@19.3.0) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + '@libsql/client@0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: '@libsql/core': 0.17.3 @@ -14006,6 +13643,30 @@ snapshots: '@nornagon/put@0.0.8': {} + '@noxcturnal/noxcturnal-darwin-arm64@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-darwin-x64@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-linux-arm64-gnu@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-linux-arm64-musl@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-linux-x64-gnu@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-linux-x64-musl@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-win32-arm64-msvc@0.1.1': + optional: true + + '@noxcturnal/noxcturnal-win32-x64-msvc@0.1.1': + optional: true + '@octokit/auth-token@6.0.0': {} '@octokit/core@7.0.6': @@ -14216,6 +13877,8 @@ snapshots: '@oxc-project/types@0.127.0': optional: true + '@oxc-project/types@0.141.0': {} + '@oxc-project/types@0.146.0': {} '@oxc-project/types@0.147.0': {} @@ -14444,16 +14107,16 @@ snapshots: tslib: 2.8.1 webcrypto-core: 1.9.2 - '@pierre/diffs@1.3.0-beta.10(patch_hash=0ccee155b93b63d810e2c1a40c1fd676fb6fbcfa72cf6430dcedf1a3ae475ab4)(@shikijs/themes@4.2.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@pierre/diffs@1.3.0-beta.10(patch_hash=0ccee155b93b63d810e2c1a40c1fd676fb6fbcfa72cf6430dcedf1a3ae475ab4)(@shikijs/themes@4.2.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@pierre/theme': 1.1.0 - '@pierre/theming': 0.0.2(@pierre/theme@1.1.0)(@shikijs/themes@4.2.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(shiki@4.2.0) + '@pierre/theming': 0.0.2(@pierre/theme@1.1.0)(@shikijs/themes@4.2.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(shiki@4.2.0) '@shikijs/transformers': 4.2.0 diff: 9.0.0 hast-util-to-html: 9.0.5 lru_map: 0.4.1 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) shiki: 4.2.0 transitivePeerDependencies: - '@shikijs/themes' @@ -14474,12 +14137,12 @@ snapshots: '@pierre/theme@1.1.0': {} - '@pierre/theming@0.0.2(@pierre/theme@1.1.0)(@shikijs/themes@4.2.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(shiki@4.2.0)': + '@pierre/theming@0.0.2(@pierre/theme@1.1.0)(@shikijs/themes@4.2.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(shiki@4.2.0)': optionalDependencies: '@pierre/theme': 1.1.0 '@shikijs/themes': 4.2.0 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) shiki: 4.2.0 '@pierre/theming@0.0.2(@pierre/theme@1.1.0)(@shikijs/themes@4.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(shiki@4.2.0)': @@ -14490,19 +14153,19 @@ snapshots: react-dom: 19.2.6(react@19.2.6) shiki: 4.2.0 - '@pierre/trees@1.0.0-beta.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@pierre/trees@1.0.0-beta.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: preact: 11.0.0-beta.0 preact-render-to-string: 6.6.5(preact@11.0.0-beta.0) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) - '@pierre/trees@1.0.0-beta.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@pierre/trees@1.0.0-beta.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: preact: 11.0.0-beta.0 preact-render-to-string: 6.6.5(preact@11.0.0-beta.0) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) '@polka/url@1.0.0-next.29': {} @@ -14513,149 +14176,6 @@ snapshots: optionalDependencies: yauzl: 3.4.0 - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.16)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-context@1.1.2(@types/react@19.2.16)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.16)(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.2(@types/react@19.2.16)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.16)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.16)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.16)(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.16)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.16)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.16)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.16)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.16)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.16)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.16)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.16 - '@react-grab/cli@0.1.44': dependencies: agent-install: 0.0.5 @@ -14667,35 +14187,35 @@ snapshots: prompts: 2.4.2 tinyexec: 1.2.4 - '@react-native-ai/apple@0.12.0(patch_hash=2d09870c2848d185cb05b53ed823a46e12dba519324d8dd8e584e28731990f9d)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))': + '@react-native-ai/apple@0.12.0(patch_hash=2d09870c2848d185cb05b53ed823a46e12dba519324d8dd8e584e28731990f9d)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))': dependencies: '@ai-sdk/provider': 3.0.15 '@ai-sdk/provider-utils': 4.0.49(zod@4.4.3) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) zod: 4.4.3 - '@react-native-masked-view/masked-view@0.3.2(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@react-native-masked-view/masked-view@0.3.2(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) optional: true - '@react-native-menu/menu@2.0.0(patch_hash=f63d256bf6a97a873b5e628eb595bd6ef0075ddd5bdd890fc920f7a6024290dd)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@react-native-menu/menu@2.0.0(patch_hash=1cc2d43fbd0281ca0dd1feb5ffcefee7d4419459c8daaa58effff10c657832fb)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - '@react-native/assets-registry@0.86.3': {} + '@react-native/asset-utils@0.88.0-rc.3': {} - '@react-native/babel-plugin-codegen@0.86.3(@babel/core@7.29.7)': + '@react-native/babel-plugin-codegen@0.88.0-rc.3(@babel/core@7.29.7)': dependencies: '@babel/traverse': 7.29.7 - '@react-native/codegen': 0.86.3(@babel/core@7.29.7) + '@react-native/codegen': 0.88.0-rc.3(@babel/core@7.29.7) transitivePeerDependencies: - '@babel/core' - supports-color - '@react-native/babel-preset@0.86.3(@babel/core@7.29.7)': + '@react-native/babel-preset@0.88.0-rc.3(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 '@babel/plugin-proposal-export-default-from': 7.29.7(@babel/core@7.29.7) @@ -14726,42 +14246,42 @@ snapshots: '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) - '@react-native/babel-plugin-codegen': 0.86.3(@babel/core@7.29.7) - babel-plugin-syntax-hermes-parser: 0.36.0 + '@react-native/babel-plugin-codegen': 0.88.0-rc.3(@babel/core@7.29.7) babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.29.7) + flow-parser: 0.327.0 react-refresh: 0.14.2 transitivePeerDependencies: - supports-color - '@react-native/codegen@0.86.3(@babel/core@7.29.7)': + '@react-native/codegen@0.88.0-rc.3(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 - hermes-parser: 0.36.0 + '@babel/parser': 7.29.8 + flow-parser: 0.327.0 invariant: 2.2.4 nullthrows: 1.1.1 tinyglobby: 0.2.17 yargs: 17.7.2 - '@react-native/community-cli-plugin@0.86.3(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + '@react-native/community-cli-plugin@0.88.0-rc.3(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: - '@react-native/dev-middleware': 0.86.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@react-native/asset-utils': 0.88.0-rc.3 + '@react-native/dev-middleware': 0.88.0-rc.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) + commander: 12.1.0 debug: 4.4.3 invariant: 2.2.4 - metro: 0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-config: 0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-core: 0.84.4 + metro: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) semver: 7.8.5 optionalDependencies: - '@react-native/metro-config': 0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@react-native/metro-config': 0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - '@react-native/debugger-frontend@0.86.3': {} + '@react-native/debugger-frontend@0.88.0-rc.3': {} - '@react-native/debugger-shell@0.86.3': + '@react-native/debugger-shell@0.88.0-rc.3': dependencies: cross-spawn: 7.0.6 debug: 4.4.3 @@ -14769,18 +14289,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-native/dev-middleware@0.86.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + '@react-native/dev-middleware@0.88.0-rc.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: '@isaacs/ttlcache': 1.4.1 - '@react-native/debugger-frontend': 0.86.3 - '@react-native/debugger-shell': 0.86.3 - chrome-launcher: 0.15.2 - chromium-edge-launcher: 0.3.0 + '@react-native/debugger-frontend': 0.88.0-rc.3 + '@react-native/debugger-shell': 0.88.0-rc.3 connect: 3.7.0 debug: 4.4.3 invariant: 2.2.4 nullthrows: 1.1.1 - open: 7.4.2 + open: 8.4.2 serve-static: 1.16.3 ws: 7.5.11(bufferutil@4.1.0)(utf-8-validate@6.0.6) transitivePeerDependencies: @@ -14788,100 +14306,90 @@ snapshots: - supports-color - utf-8-validate - '@react-native/gradle-plugin@0.86.3': {} + '@react-native/gradle-plugin@0.88.0-rc.3': {} - '@react-native/js-polyfills@0.86.3': {} + '@react-native/js-polyfills@0.88.0-rc.3': {} - '@react-native/metro-babel-transformer@0.86.3(@babel/core@7.29.7)': + '@react-native/metro-babel-transformer@0.88.0-rc.3(@babel/core@7.29.7)': dependencies: '@babel/core': 7.29.7 - '@react-native/babel-preset': 0.86.3(@babel/core@7.29.7) - hermes-parser: 0.36.0 + '@react-native/babel-preset': 0.88.0-rc.3(@babel/core@7.29.7) + flow-parser: 0.327.0 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - '@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6)': + '@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: - '@react-native/js-polyfills': 0.86.3 - '@react-native/metro-babel-transformer': 0.86.3(@babel/core@7.29.7) - metro-config: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-runtime: 0.84.5 + '@react-native/js-polyfills': 0.88.0-rc.3 + '@react-native/metro-babel-transformer': 0.88.0-rc.3(@babel/core@7.29.7) + metro-config: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + metro-runtime: 0.87.1 transitivePeerDependencies: - '@babel/core' - bufferutil - supports-color - utf-8-validate - '@react-native/normalize-colors@0.86.3': {} + '@react-native/normalize-colors@0.88.0-rc.3': {} - '@react-native/virtualized-lists@0.86.3(@types/react@19.2.16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@react-native/virtualized-lists@0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 - '@react-native/virtualized-lists@0.86.3(@types/react@19.2.16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)': - dependencies: - invariant: 2.2.4 - nullthrows: 1.1.1 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optionalDependencies: - '@types/react': 19.2.16 - optional: true - - '@react-navigation/core@7.21.13(react@19.2.3)': + '@react-navigation/core@7.21.13(react@19.3.0)': dependencies: '@react-navigation/routers': 7.6.4 escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.19 query-string: 7.1.3 - react: 19.2.3 + react: 19.3.0 react-is: 19.2.7 - use-latest-callback: 0.2.6(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) + use-latest-callback: 0.2.6(react@19.3.0) + use-sync-external-store: 1.6.0(react@19.3.0) - '@react-navigation/elements@2.9.26(c10301b6e0c42fc6434d2b643197a81e)': + '@react-navigation/elements@2.9.26(83de68753219ecf7f3321e065bd378be)': dependencies: - '@react-navigation/native': 7.3.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + '@react-navigation/native': 7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) color: 4.2.3 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-safe-area-context: 5.7.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - use-latest-callback: 0.2.6(react@19.2.3) - use-sync-external-store: 1.6.0(react@19.2.3) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-safe-area-context: 5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + use-latest-callback: 0.2.6(react@19.3.0) + use-sync-external-store: 1.6.0(react@19.3.0) optionalDependencies: - '@react-native-masked-view/masked-view': 0.3.2(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + '@react-native-masked-view/masked-view': 0.3.2(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - '@react-navigation/native-stack@7.17.6(patch_hash=e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552)(f640afa6cd4b9a1dc5422cbafdc82f53)': + '@react-navigation/native-stack@7.17.6(patch_hash=e667c3cef8c78bb9ff4882ee5bd23a432247b843060a9499eb5f07e9e2295552)(cdeee8948497d4b80ffe015e2a003650)': dependencies: - '@react-navigation/elements': 2.9.26(c10301b6e0c42fc6434d2b643197a81e) - '@react-navigation/native': 7.3.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + '@react-navigation/elements': 2.9.26(83de68753219ecf7f3321e065bd378be) + '@react-navigation/native': 7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) color: 4.2.3 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-safe-area-context: 5.7.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react-native-screens: 4.26.2(patch_hash=595114f3f9ce8b9f0d99d1aafe5c12c997b7d75ca9add31d46cbedbfe347b8e0)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-safe-area-context: 5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react-native-screens: 4.28.0(patch_hash=cc1301436ee62c39860acc9ee1a1e60b7d47e6abd211c42effa62c056d165483)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) sf-symbols-typescript: 2.2.0 warn-once: 0.1.1 transitivePeerDependencies: - '@react-native-masked-view/masked-view' - '@react-navigation/native@7.3.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)': + '@react-navigation/native@7.3.4(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - '@react-navigation/core': 7.21.13(react@19.2.3) + '@react-navigation/core': 7.21.13(react@19.3.0) escape-string-regexp: 4.0.0 fast-deep-equal: 3.1.3 nanoid: 3.3.19 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) standard-navigation: 0.0.7 - use-latest-callback: 0.2.6(react@19.2.3) + use-latest-callback: 0.2.6(react@19.3.0) '@react-navigation/routers@7.6.4': dependencies: @@ -15153,28 +14661,28 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@t3tools/mobile-markdown-text@file:apps/mobile/modules/t3-markdown-text(c883758f8793b29a89016166016b354e)': + '@t3tools/mobile-markdown-text@file:apps/mobile/modules/t3-markdown-text(5c46709ff7a3b3b481fcdaa30ae2beb2)': dependencies: '@t3tools/client-runtime': link:packages/client-runtime '@t3tools/shared': link:packages/shared - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-asset: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) - expo-clipboard: 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo-haptics: 57.0.2(expo@57.0.18) - expo-symbols: 57.0.2(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-nitro-markdown: 0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-clipboard: 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-haptics: 58.0.3(expo@58.0.0) + expo-symbols: 58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-nitro-markdown: 0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@t3tools/mobile-review-diff-native@file:apps/mobile/modules/t3-review-diff': {} '@t3tools/mobile-terminal-native@file:apps/mobile/modules/t3-terminal': {} - '@tabler/icons-react-native@3.44.0(react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react@19.2.3)': + '@tabler/icons-react-native@3.44.0(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react@19.3.0)': dependencies: '@tabler/icons': 3.44.0 - react: 19.2.3 - react-native-svg: 15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react: 19.3.0 + react-native-svg: 15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@tabler/icons@3.44.0': {} @@ -15296,7 +14804,7 @@ snapshots: '@tanstack/router-generator@1.167.12': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@tanstack/router-core': 1.171.8 '@tanstack/router-utils': 1.162.1 '@tanstack/virtual-file-routes': 1.162.0 @@ -15333,7 +14841,7 @@ snapshots: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 ansis: 4.3.1 babel-dead-code-elimination: 1.0.12 diff: 8.0.3 @@ -15500,12 +15008,12 @@ snapshots: prosemirror-transform: 1.12.1 prosemirror-view: 1.42.3 - '@tiptap/react@3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@tiptap/react@3.31.3(@floating-ui/dom@1.7.6)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.3(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) '@tiptap/pm': 3.31.3 - '@types/react': 19.2.16 - '@types/react-dom': 19.2.3(@types/react@19.2.16) + '@types/react': 19.3.0 + '@types/react-dom': 19.2.3(@types/react@19.3.0) '@types/use-sync-external-store': 0.0.6 fast-equals: 5.4.2 react: 19.2.6 @@ -15570,16 +15078,16 @@ snapshots: '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 '@types/body-parser@1.19.6': dependencies: @@ -15640,8 +15148,6 @@ snapshots: dependencies: '@types/node': 24.12.4 - '@types/hammerjs@2.0.46': {} - '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -15696,15 +15202,15 @@ snapshots: '@types/range-parser@1.2.7': {} - '@types/react-dom@19.2.3(@types/react@19.2.16)': + '@types/react-dom@19.2.3(@types/react@19.3.0)': dependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 '@types/react-test-renderer@19.1.0': dependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 - '@types/react@19.2.16': + '@types/react@19.3.0': dependencies: csstype: 3.2.3 @@ -16185,7 +15691,7 @@ snapshots: agent-base@7.1.4: {} - agent-cli-detector@0.1.6: {} + agent-cli-detector@0.1.7: {} agent-install@0.0.5: dependencies: @@ -16228,12 +15734,12 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ? alchemy@2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.2.16)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(31bc26b129d6bba2f2e387113f50dba2))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ? alchemy@2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) : dependencies: '@alchemy.run/cloudflare-runtime': 2.0.0-beta.79(@distilled.cloud/cloudflare@1.0.0-rc.12(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@types/node@24.12.4)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(rolldown@1.2.5)(typescript@7.0.2) '@alchemy.run/floci': 2.0.0-beta.79(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) '@alchemy.run/node-utils': 2.0.0-beta.79 - '@alchemy.run/sigil': 0.0.0-alpha.11(@types/react@19.2.16)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@alchemy.run/sigil': 0.0.0-alpha.11(@types/react@19.3.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6)) '@aws-sdk/credential-providers': 3.1062.0 '@distilled.cloud/aws': 1.0.0-rc.12(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) '@distilled.cloud/axiom': 1.0.0-rc.12(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) @@ -16268,7 +15774,7 @@ snapshots: '@effect/platform-node': 4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6) '@effect/sql-pg': 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) drizzle-kit: 1.0.0-rc.5-ab785fc - drizzle-orm: 1.0.0-rc.5-ab785fc(31bc26b129d6bba2f2e387113f50dba2) + drizzle-orm: 1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150) mongodb: 6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9) pg: 8.23.0 vite: '@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0)' @@ -16375,10 +15881,6 @@ snapshots: argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -16512,9 +16014,9 @@ snapshots: babel-dead-code-elimination@1.0.12: dependencies: '@babel/core': 7.29.7 - '@babel/parser': 7.29.7 + '@babel/parser': 7.29.8 '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color @@ -16548,10 +16050,6 @@ snapshots: babel-plugin-react-native-web@0.21.2: {} - babel-plugin-syntax-hermes-parser@0.36.0: - dependencies: - hermes-parser: 0.36.0 - babel-plugin-syntax-hermes-parser@0.36.1: dependencies: hermes-parser: 0.36.1 @@ -16562,7 +16060,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - babel-preset-expo@57.0.9(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@57.0.15)(expo@57.0.18)(react-refresh@0.14.2): + babel-preset-expo@58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.7 '@babel/helper-module-imports': 7.29.7 @@ -16593,14 +16091,14 @@ snapshots: '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-react-jsx-development': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-react-pure-annotations': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-runtime': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) - '@react-native/babel-plugin-codegen': 0.86.3(@babel/core@7.29.7) + '@react-native/babel-plugin-codegen': 0.88.0-rc.3(@babel/core@7.29.7) babel-plugin-react-compiler: 1.0.0 babel-plugin-react-native-web: 0.21.2 babel-plugin-syntax-hermes-parser: 0.36.1 @@ -16609,8 +16107,8 @@ snapshots: react-refresh: 0.14.2 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-widgets: 57.0.15(patch_hash=319a9ded5db49c5b5215c511a138b33f44c7ea2972eb418192e8d5342fe75ce6)(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-widgets: 58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -16829,29 +16327,8 @@ snapshots: chownr@3.0.0: {} - chrome-launcher@0.15.2: - dependencies: - '@types/node': 24.12.4 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - transitivePeerDependencies: - - supports-color - - chromium-edge-launcher@0.3.0: - dependencies: - '@types/node': 24.12.4 - escape-string-regexp: 4.0.0 - is-wsl: 2.2.0 - lighthouse-logger: 1.4.2 - mkdirp: 1.0.4 - transitivePeerDependencies: - - supports-color - chromium-pickle-js@0.2.0: {} - ci-info@2.0.0: {} - ci-info@3.9.0: {} ci-info@4.3.1: {} @@ -17150,6 +16627,8 @@ snapshots: gopd: 1.2.0 optional: true + define-lazy-prop@2.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 @@ -17176,8 +16655,6 @@ snapshots: detect-libc@2.1.2: {} - detect-node-es@1.1.0: {} - detect-node@2.1.0: optional: true @@ -17206,7 +16683,7 @@ snapshots: - electron-builder-squirrel-windows - supports-color - dnssd-advertise@1.1.4: {} + dnssd-advertise@1.1.6: {} dom-accessibility-api@0.5.16: {} @@ -17246,7 +16723,7 @@ snapshots: get-tsconfig: 4.14.3 jiti: 2.7.0 - drizzle-orm@1.0.0-rc.5-ab785fc(31bc26b129d6bba2f2e387113f50dba2): + drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150): optionalDependencies: '@cloudflare/workers-types': 4.20260604.1 '@effect/sql-d1': 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) @@ -17257,7 +16734,7 @@ snapshots: '@libsql/client': 0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) bun-types: 1.3.14 effect: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) - expo-sqlite: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) + expo-sqlite: 58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) pg: 8.23.0 valibot: 1.2.0(typescript@7.0.2) zod: 4.4.3 @@ -17526,231 +17003,195 @@ snapshots: expect-type@1.4.0: {} - expo-application@57.0.2(expo@57.0.18): + expo-application@58.0.2(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-asset@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2): + expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - '@expo/image-utils': 0.11.5(typescript@7.0.2) - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + '@expo/image-utils': 0.12.2(typescript@7.0.2) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-asset@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)(typescript@7.0.2): + expo-audio@58.0.3(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - '@expo/image-utils': 0.11.5(typescript@7.0.2) - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)) - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - transitivePeerDependencies: - - supports-color - - typescript - optional: true - - expo-audio@57.0.4(patch_hash=fa9a3e0442ed395d4071bb406e08c3a471c9a84700bdfa0b9ad7ff144c96041a)(expo-asset@57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): - dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-asset: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-auth-session@57.0.10(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-auth-session@58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - expo-application: 57.0.2(expo@57.0.18) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-crypto: 57.0.2(expo@57.0.18) - expo-linking: 57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo-web-browser: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + expo-application: 58.0.2(expo@58.0.0) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-crypto: 58.0.3(expo@58.0.0) + expo-linking: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-web-browser: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) invariant: 2.2.4 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - expo - supports-color + - typescript - expo-blur@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-blur@58.0.2(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-build-properties@57.0.15(expo@57.0.18): + expo-build-properties@58.0.9(expo@58.0.0): dependencies: - '@expo/schema-utils': 57.0.2 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + '@expo/schema-utils': 58.0.1 + expo: 58.0.0(3abfa3879936d948a635873738556226) resolve-from: 5.0.0 semver: 7.8.5 - expo-camera@57.0.4(@types/emscripten@1.41.5)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-camera@58.0.5(@types/emscripten@1.41.5)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: barcode-detector: 3.2.0(@types/emscripten@1.41.5) - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - '@types/emscripten' - expo-clipboard@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): - dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - - expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-clipboard@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - '@expo/env': 2.4.3 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - transitivePeerDependencies: - - supports-color + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)): + expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2): dependencies: - '@expo/env': 2.4.3 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) + '@expo/env': 2.5.1 + '@expo/require-utils': 58.0.2(typescript@7.0.2) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - optional: true + - typescript - expo-crypto@57.0.2(expo@57.0.18): + expo-crypto@58.0.3(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-dev-launcher: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-dev-menu: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-dev-menu-interface: 57.0.0(expo@57.0.18) - expo-manifests: 57.0.1(expo@57.0.18) - expo-updates-interface: 57.0.1(expo@57.0.18) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-dev-launcher: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-dev-menu: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-dev-menu-interface: 58.0.1(expo@58.0.0) + expo-manifests: 58.0.1(expo@58.0.0) + expo-updates-interface: 58.0.1(expo@58.0.0) transitivePeerDependencies: - react-native - expo-dev-launcher@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-dev-launcher@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - '@expo/schema-utils': 57.0.2 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-dev-menu: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-manifests: 57.0.1(expo@57.0.18) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + '@expo/schema-utils': 58.0.1 + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-dev-menu: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-manifests: 58.0.1(expo@58.0.0) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-dev-menu-interface@57.0.0(expo@57.0.18): + expo-dev-menu-interface@58.0.1(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-dev-menu@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-dev-menu@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-dev-menu-interface: 57.0.0(expo@57.0.18) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-dev-menu-interface: 58.0.1(expo@58.0.0) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-device@57.0.1(expo@57.0.18): + expo-device@58.0.3(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) ua-parser-js: 0.7.41 - expo-document-picker@57.0.1(expo@57.0.18): + expo-document-picker@58.0.3(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-eas-client@57.0.2: {} + expo-eas-client@58.0.1: {} - expo-file-system@57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-file-system@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-file-system@57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)): + expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-glass-effect@58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - fontfaceobserver: 2.3.0 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6): + expo-haptics@58.0.3(expo@58.0.0): dependencies: - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - fontfaceobserver: 2.3.0 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true - - expo-glass-effect@57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): - dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - - expo-haptics@57.0.2(expo@57.0.18): - dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-image-loader@57.0.1(expo@57.0.18): + expo-image-loader@58.0.2(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-image-manipulator@57.0.17(expo@57.0.18): + expo-image-manipulator@58.0.10(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-image-loader: 57.0.1(expo@57.0.18) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-image-loader: 58.0.2(expo@58.0.0) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-image-picker@57.0.14(expo@57.0.18): + expo-image-picker@58.0.9(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-image-loader: 57.0.1(expo@57.0.18) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-image-loader: 58.0.2(expo@58.0.0) - expo-image@57.0.3(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-image@58.0.8(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 - expo-json-utils@57.0.1: {} + expo-json-utils@58.0.1: {} - expo-keep-awake@57.0.2(expo@57.0.18)(react@19.2.3): + expo-keep-awake@58.0.2(expo@58.0.0)(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 - expo-keep-awake@57.0.2(expo@57.0.18)(react@19.2.6): + expo-linking@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react: 19.2.6 - optional: true - - expo-linking@57.0.8(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): - dependencies: - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) invariant: 2.2.4 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - - expo - supports-color + - typescript - expo-manifests@57.0.1(expo@57.0.18): + expo-manifests@58.0.1(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-json-utils: 57.0.1 + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-json-utils: 58.0.1 - expo-modules-autolinking@57.0.12(typescript@7.0.2): + expo-modules-autolinking@58.0.6(typescript@7.0.2): dependencies: - '@expo/require-utils': 57.0.5(typescript@7.0.2) + '@expo/require-utils': 58.0.2(typescript@7.0.2) '@expo/spawn-async': 1.8.0 chalk: 4.1.2 commander: 7.2.0 @@ -17758,253 +17199,187 @@ snapshots: - supports-color - typescript - expo-modules-core@57.0.14(patch_hash=6be7092f8c6f03a57b75c797d98b5f19ed62d2dd205bfc4c8adf4cef45655d7e)(react-native-worklets@0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6): - dependencies: - '@expo/expo-modules-macros-plugin': 0.6.1 - expo-modules-jsi: 57.0.6(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)) - invariant: 2.2.4 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optionalDependencies: - react-native-worklets: 0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - optional: true - - expo-modules-core@57.0.14(patch_hash=6be7092f8c6f03a57b75c797d98b5f19ed62d2dd205bfc4c8adf4cef45655d7e)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-modules-core@58.0.9(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - '@expo/expo-modules-macros-plugin': 0.6.1 - expo-modules-jsi: 57.0.6(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + expo-modules-jsi: 58.0.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-modules-macros: 0.14.0 invariant: 2.2.4 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) optionalDependencies: - react-native-worklets: 0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react-native-worklets: 0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo-modules-jsi@57.0.6(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-modules-jsi@58.0.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-modules-jsi@57.0.6(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)): - dependencies: - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true + expo-modules-macros@0.14.0: {} - expo-network@57.0.1(expo@57.0.18)(react@19.2.3): + expo-network@58.0.2(expo@58.0.0)(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 - expo-notifications@57.0.15(patch_hash=f89252c2c08dc7b3acb8415f319ebbe15fff8c9f88a64ebe1830cd5ac5c9ac40)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2): + expo-notifications@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - '@expo/image-utils': 0.11.5(typescript@7.0.2) + '@expo/image-utils': 0.12.2(typescript@7.0.2) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-application: 57.0.2(expo@57.0.18) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-application: 58.0.2(expo@58.0.0) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-paste-input@0.1.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-paste-input@0.1.15(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-quick-actions@6.0.2(expo@57.0.18)(typescript@7.0.2): + expo-quick-actions@6.0.2(expo@58.0.0)(typescript@7.0.2): dependencies: '@expo/image-utils': 0.8.14(typescript@7.0.2) - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) schema-utils: 4.3.3 sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - supports-color - typescript - expo-secure-store@57.0.2(expo@57.0.18): + expo-secure-store@58.0.1(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-server@57.0.3: {} + expo-server@58.0.2: {} - expo-sharing@57.0.17(patch_hash=8d2e3b10eb3f52036a9a086800180ec6cebf3b75bccc5b1775117a7244d4ac45)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2): + expo-sharing@58.0.12(patch_hash=5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/config-types': 57.0.2 - '@expo/plist': 0.8.1 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) + '@expo/config-types': 58.0.2 + '@expo/plist': 0.10.1 + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-splash-screen@57.0.8(expo@57.0.18)(typescript@7.0.2): + expo-splash-screen@58.0.2(expo@58.0.0)(typescript@7.0.2): dependencies: - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/image-utils': 0.11.5(typescript@7.0.2) - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) + '@expo/image-utils': 0.12.2(typescript@7.0.2) + expo: 58.0.0(3abfa3879936d948a635873738556226) xml2js: 0.6.0 transitivePeerDependencies: - supports-color - typescript - expo-sqlite@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-sqlite@58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: await-lock: 2.2.2 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-sqlite@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6): - dependencies: - await-lock: 2.2.2 - expo: 57.0.18(0bf40d5ad6281d8f1e92517b24812edb) - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true - - expo-structured-headers@57.0.0: {} + expo-structured-headers@58.0.1: {} - expo-symbols@57.0.2(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-symbols@58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@expo-google-fonts/material-symbols': 0.4.38 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 - expo-updates-interface@57.0.1(expo@57.0.18): + expo-updates-interface@58.0.1(expo@58.0.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) + expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-updates@57.0.19(expo-dev-client@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-updates@58.0.11(expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@expo/code-signing-certificates': 0.0.6 - '@expo/plist': 0.8.1 + '@expo/plist': 0.10.1 '@expo/spawn-async': 1.8.0 arg: 4.1.3 chalk: 4.1.2 debug: 4.4.3 - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - expo-eas-client: 57.0.2 - expo-manifests: 57.0.1(expo@57.0.18) - expo-structured-headers: 57.0.0 - expo-updates-interface: 57.0.1(expo@57.0.18) + expo: 58.0.0(3abfa3879936d948a635873738556226) + expo-eas-client: 58.0.1 + expo-manifests: 58.0.1(expo@58.0.0) + expo-structured-headers: 58.0.1 + expo-updates-interface: 58.0.1(expo@58.0.0) getenv: 2.0.0 glob: 13.0.6 ignore: 5.3.2 nullthrows: 1.1.1 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) resolve-from: 5.0.0 optionalDependencies: - expo-dev-client: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) + expo-dev-client: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) transitivePeerDependencies: - supports-color - expo-video@57.0.3(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-video@58.0.5(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-web-browser@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): + expo-web-browser@58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-widgets@57.0.15(patch_hash=319a9ded5db49c5b5215c511a138b33f44c7ea2972eb418192e8d5342fe75ce6)(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + expo-widgets@58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - '@expo/plist': 0.8.1 - '@expo/ui': 57.0.14(@babel/core@7.29.7)(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo: 57.0.18(41fd11498a34454c91128cdad32f22f8) - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + '@expo/plist': 0.10.1 + '@expo/ui': 58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.0(3abfa3879936d948a635873738556226) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - '@babel/core' - - '@types/react' - - '@types/react-dom' - react-dom - react-native-worklets - expo@57.0.18(0bf40d5ad6281d8f1e92517b24812edb): - dependencies: - '@babel/runtime': 7.29.7 - '@expo/cli': 57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(bufferutil@4.1.0)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)(typescript@7.0.2)(utf-8-validate@6.0.6) - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/devtools': 57.0.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - '@expo/fingerprint': 0.20.11 - '@expo/local-build-cache-provider': 57.0.8(typescript@7.0.2) - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - '@expo/metro': 56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6) - '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 57.0.9(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@57.0.15)(expo@57.0.18)(react-refresh@0.14.2) - expo-asset: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6)(typescript@7.0.2) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)) - expo-file-system: 57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6)) - expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - expo-keep-awake: 57.0.2(expo@57.0.18)(react@19.2.6) - expo-modules-autolinking: 57.0.12(typescript@7.0.2) - expo-modules-core: 57.0.14(patch_hash=6be7092f8c6f03a57b75c797d98b5f19ed62d2dd205bfc4c8adf4cef45655d7e)(react-native-worklets@0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - pretty-format: 29.7.0 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - react-refresh: 0.14.2 - whatwg-url-minimum: 0.1.2 - optionalDependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.6(react@19.2.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - react-dom: 19.2.6(react@19.2.6) - react-native-webview: 13.16.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - transitivePeerDependencies: - - '@babel/core' - - bufferutil - - expo-router - - expo-widgets - - react-native-worklets - - react-server-dom-webpack - - supports-color - - typescript - - utf-8-validate - optional: true - - expo@57.0.18(41fd11498a34454c91128cdad32f22f8): + expo@58.0.0(3abfa3879936d948a635873738556226): dependencies: '@babel/runtime': 7.29.7 - '@expo/cli': 57.0.20(@expo/dom-webview@57.0.1)(@expo/metro-runtime@57.0.14)(bufferutil@4.1.0)(expo-constants@57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)))(expo-font@57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2)(utf-8-validate@6.0.6) - '@expo/config': 57.0.9(typescript@7.0.2) - '@expo/config-plugins': 57.0.9(typescript@7.0.2) - '@expo/devtools': 57.0.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - '@expo/fingerprint': 0.20.11 - '@expo/local-build-cache-provider': 57.0.8(typescript@7.0.2) - '@expo/log-box': 57.0.4(@expo/dom-webview@57.0.1)(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - '@expo/metro': 56.0.2(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/cli': 58.0.9(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.9)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/config': 58.0.1(typescript@7.0.2) + '@expo/config-plugins': 58.0.4(typescript@7.0.2) + '@expo/devtools': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/fingerprint': 0.21.2 + '@expo/local-build-cache-provider': 58.0.1(typescript@7.0.2) + '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box-utils': 58.0.1 + '@expo/metro': 58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 57.0.9(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@57.0.15)(expo@57.0.18)(react-refresh@0.14.2) - expo-asset: 57.0.15(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(typescript@7.0.2) - expo-constants: 57.0.16(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-file-system: 57.0.6(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)) - expo-font: 57.0.2(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - expo-keep-awake: 57.0.2(expo@57.0.18)(react@19.2.3) - expo-modules-autolinking: 57.0.12(typescript@7.0.2) - expo-modules-core: 57.0.14(patch_hash=6be7092f8c6f03a57b75c797d98b5f19ed62d2dd205bfc4c8adf4cef45655d7e)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + babel-preset-expo: 58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2) + expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-file-system: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-keep-awake: 58.0.2(expo@58.0.0)(react@19.3.0) + expo-modules-autolinking: 58.0.6(typescript@7.0.2) + expo-modules-core: 58.0.9(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) pretty-format: 29.7.0 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) react-refresh: 0.14.2 - whatwg-url-minimum: 0.1.2 + whatwg-url-minimum: 0.2.0 optionalDependencies: - '@expo/dom-webview': 57.0.1(expo@57.0.18)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - '@expo/metro-runtime': 57.0.14(@expo/log-box@57.0.4)(expo@57.0.18)(react-dom@19.2.3(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react-dom: 19.2.3(react@19.2.3) - react-native-webview: 13.16.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + '@expo/dom-webview': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/metro-runtime': 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react-dom: 19.3.0(react@19.3.0) + react-native-webview: 14.0.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -18185,12 +17560,22 @@ snapshots: flow-enums-runtime@0.0.6: {} + flow-estree@0.327.0: {} + + flow-estree@0.331.0: {} + + flow-parser@0.327.0: + dependencies: + flow-estree: 0.327.0 + + flow-parser@0.331.0: + dependencies: + flow-estree: 0.331.0 + fontace@0.4.1: dependencies: fontkitten: 1.0.3 - fontfaceobserver@2.3.0: {} - fontkitten@1.0.3: dependencies: tiny-inflate: 1.0.3 @@ -18279,8 +17664,6 @@ snapshots: hasown: 2.0.4 math-intrinsics: 1.1.0 - get-nonce@1.0.1: {} - get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -18487,32 +17870,16 @@ snapshots: heic-to@1.5.2: {} - hermes-compiler@250829098.0.17: {} - - hermes-estree@0.35.0: {} - - hermes-estree@0.36.0: {} + hermes-compiler@260318099.0.4: {} hermes-estree@0.36.1: {} - hermes-parser@0.35.0: - dependencies: - hermes-estree: 0.35.0 - - hermes-parser@0.36.0: - dependencies: - hermes-estree: 0.36.0 - hermes-parser@0.36.1: dependencies: hermes-estree: 0.36.1 hexy@0.2.11: {} - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 - hono@4.13.7: {} hosted-git-info@4.1.0: @@ -18582,10 +17949,6 @@ snapshots: ignore@7.0.5: {} - image-size@1.2.1: - dependencies: - queue: 6.0.2 - immediate@3.0.6: {} inflight@1.0.6: @@ -18865,13 +18228,6 @@ snapshots: dependencies: immediate: 3.0.6 - lighthouse-logger@1.4.2: - dependencies: - debug: 2.6.9 - marky: 1.3.0 - transitivePeerDependencies: - - supports-color - lightningcss-android-arm64@1.33.0: optional: true @@ -19001,8 +18357,6 @@ snapshots: markdown-table@3.0.4: {} - marky@1.3.0: {} - matcher@3.0.0: dependencies: escape-string-regexp: 4.0.0 @@ -19201,109 +18555,50 @@ snapshots: meshoptimizer@0.22.0: {} - metro-babel-transformer@0.84.4: + metro-babel-transformer@0.87.1: dependencies: '@babel/core': 7.29.7 flow-enums-runtime: 0.0.6 - hermes-parser: 0.35.0 - metro-cache-key: 0.84.4 + flow-parser: 0.331.0 + metro-cache-key: 0.87.1 nullthrows: 1.1.1 transitivePeerDependencies: - supports-color - metro-babel-transformer@0.84.5: + metro-cache-key@0.87.1: dependencies: - '@babel/core': 7.29.7 flow-enums-runtime: 0.0.6 - hermes-parser: 0.35.0 - metro-cache-key: 0.84.5 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - metro-cache-key@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-cache-key@0.84.5: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-cache@0.84.4: + metro-cache@0.87.1: dependencies: exponential-backoff: 3.1.3 flow-enums-runtime: 0.0.6 https-proxy-agent: 7.0.6 - metro-core: 0.84.4 + metro-core: 0.87.1 transitivePeerDependencies: - supports-color - metro-cache@0.84.5: - dependencies: - exponential-backoff: 3.1.3 - flow-enums-runtime: 0.0.6 - https-proxy-agent: 7.0.6 - metro-core: 0.84.5 - transitivePeerDependencies: - - supports-color - - metro-config@0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6): + metro-config@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: connect: 3.7.0 flow-enums-runtime: 0.0.6 jest-validate: 29.7.0 - metro: 0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-cache: 0.84.4 - metro-core: 0.84.4 - metro-runtime: 0.84.4 - yaml: 2.9.0 + metro: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + metro-cache: 0.87.1 + metro-core: 0.87.1 + metro-runtime: 0.87.1 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - metro-config@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6): - dependencies: - connect: 3.7.0 - flow-enums-runtime: 0.0.6 - jest-validate: 29.7.0 - metro: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-cache: 0.84.5 - metro-core: 0.84.5 - metro-runtime: 0.84.5 - yaml: 2.9.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro-core@0.84.4: + metro-core@0.87.1: dependencies: flow-enums-runtime: 0.0.6 lodash.throttle: 4.1.1 - metro-resolver: 0.84.4 - - metro-core@0.84.5: - dependencies: - flow-enums-runtime: 0.0.6 - lodash.throttle: 4.1.1 - metro-resolver: 0.84.5 - - metro-file-map@0.84.4: - dependencies: - debug: 4.4.3 - fb-watchman: 2.0.2 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - invariant: 2.2.4 - jest-worker: 29.7.0 - micromatch: 4.0.8 - nullthrows: 1.1.1 - walker: 1.0.8 - transitivePeerDependencies: - - supports-color + metro-resolver: 0.87.1 - metro-file-map@0.84.5: + metro-file-map@0.87.1: dependencies: debug: 4.4.3 fb-watchman: 2.0.2 @@ -19313,89 +18608,49 @@ snapshots: jest-worker: 29.7.0 micromatch: 4.0.8 nullthrows: 1.1.1 - walker: 1.0.8 transitivePeerDependencies: - supports-color - metro-minify-terser@0.84.4: + metro-minify-terser@0.87.1: dependencies: flow-enums-runtime: 0.0.6 terser: 5.48.0 - metro-minify-terser@0.84.5: + metro-resolver@0.87.1: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.48.0 - - metro-resolver@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-resolver@0.84.5: - dependencies: - flow-enums-runtime: 0.0.6 - - metro-runtime@0.84.4: - dependencies: - '@babel/runtime': 7.29.7 - flow-enums-runtime: 0.0.6 - metro-runtime@0.84.5: + metro-runtime@0.87.1: dependencies: '@babel/runtime': 7.29.7 flow-enums-runtime: 0.0.6 - metro-source-map@0.84.4: - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - 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.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-source-map@0.84.5: + metro-source-map@0.87.1: dependencies: '@babel/traverse': 7.29.7 '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-symbolicate: 0.84.5 - nullthrows: 1.1.1 - ob1: 0.84.5 - source-map: 0.5.7 - vlq: 1.0.1 - transitivePeerDependencies: - - supports-color - - metro-symbolicate@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - invariant: 2.2.4 - metro-source-map: 0.84.4 + metro-symbolicate: 0.87.1 nullthrows: 1.1.1 + ob1: 0.87.1 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-symbolicate@0.84.5: + metro-symbolicate@0.87.1: dependencies: flow-enums-runtime: 0.0.6 invariant: 2.2.4 - metro-source-map: 0.84.5 + metro-source-map: 0.87.1 nullthrows: 1.1.1 source-map: 0.5.7 vlq: 1.0.1 transitivePeerDependencies: - supports-color - metro-transform-plugins@0.84.4: + metro-transform-plugins@0.87.1: dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 @@ -19406,104 +18661,27 @@ snapshots: transitivePeerDependencies: - supports-color - metro-transform-plugins@0.84.5: - dependencies: - '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - flow-enums-runtime: 0.0.6 - nullthrows: 1.1.1 - transitivePeerDependencies: - - supports-color - - metro-transform-worker@0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6): + metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 '@babel/parser': 7.29.8 '@babel/types': 7.29.8 flow-enums-runtime: 0.0.6 - metro: 0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6) - 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 + metro: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + 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 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - metro-transform-worker@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6): - dependencies: - '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/parser': 7.29.8 - '@babel/types': 7.29.8 - flow-enums-runtime: 0.0.6 - metro: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - 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 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro@0.84.4(bufferutil@4.1.0)(utf-8-validate@6.0.6): - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/core': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - accepts: 2.0.0 - ci-info: 2.0.0 - connect: 3.7.0 - debug: 4.4.3 - error-stack-parser: 2.1.4 - flow-enums-runtime: 0.0.6 - graceful-fs: 4.2.11 - hermes-parser: 0.35.0 - image-size: 1.2.1 - invariant: 2.2.4 - jest-worker: 29.7.0 - jsc-safe-url: 0.2.4 - 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) - 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) - mime-types: 3.0.2 - nullthrows: 1.1.1 - serialize-error: 2.1.0 - source-map: 0.5.7 - throat: 5.0.0 - ws: 7.5.11(bufferutil@4.1.0)(utf-8-validate@6.0.6) - yargs: 17.7.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - metro@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6): + metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 @@ -19513,29 +18691,28 @@ snapshots: '@babel/traverse': 7.29.7 '@babel/types': 7.29.8 accepts: 2.0.0 - ci-info: 2.0.0 connect: 3.7.0 debug: 4.4.3 error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 + flow-parser: 0.331.0 graceful-fs: 4.2.11 - hermes-parser: 0.35.0 invariant: 2.2.4 jest-worker: 29.7.0 jsc-safe-url: 0.2.4 lodash.throttle: 4.1.1 - metro-babel-transformer: 0.84.5 - metro-cache: 0.84.5 - metro-cache-key: 0.84.5 - metro-config: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) + metro-babel-transformer: 0.87.1 + metro-cache: 0.87.1 + metro-cache-key: 0.87.1 + metro-config: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + 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(bufferutil@4.1.0)(utf-8-validate@6.0.6) mime-types: 3.0.2 nullthrows: 1.1.1 serialize-error: 2.1.0 @@ -19812,8 +18989,6 @@ snapshots: dependencies: minimist: 1.2.8 - mkdirp@1.0.4: {} - modern-tar@0.8.5: {} mongodb-connection-string-url@3.0.2: @@ -19947,6 +19122,20 @@ snapshots: normalize-url@6.1.0: {} + noxcturnal@0.1.1: + dependencies: + '@babel/code-frame': 7.29.7 + '@oxc-project/types': 0.141.0 + optionalDependencies: + '@noxcturnal/noxcturnal-darwin-arm64': 0.1.1 + '@noxcturnal/noxcturnal-darwin-x64': 0.1.1 + '@noxcturnal/noxcturnal-linux-arm64-gnu': 0.1.1 + '@noxcturnal/noxcturnal-linux-arm64-musl': 0.1.1 + '@noxcturnal/noxcturnal-linux-x64-gnu': 0.1.1 + '@noxcturnal/noxcturnal-linux-x64-musl': 0.1.1 + '@noxcturnal/noxcturnal-win32-arm64-msvc': 0.1.1 + '@noxcturnal/noxcturnal-win32-x64-msvc': 0.1.1 + npm-package-arg@11.0.3: dependencies: hosted-git-info: 7.0.2 @@ -19991,11 +19180,7 @@ snapshots: should: 13.2.3 yaml: 2.9.0 - ob1@0.84.4: - dependencies: - flow-enums-runtime: 0.0.6 - - ob1@0.84.5: + ob1@0.87.1: dependencies: flow-enums-runtime: 0.0.6 @@ -20050,8 +19235,9 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 - open@7.4.2: + open@8.4.2: dependencies: + define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 @@ -20573,10 +19759,6 @@ snapshots: split-on-first: 1.1.0 strict-uri-encode: 2.0.0 - queue@6.0.2: - dependencies: - inherits: 2.0.4 - quick-lru@5.1.1: {} radix3@1.1.2: {} @@ -20590,13 +19772,13 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 - react-day-picker@10.0.1(@types/react@19.2.16)(react@19.2.6): + react-day-picker@10.0.1(@types/react@19.3.0)(react@19.2.6): dependencies: '@date-fns/tz': 1.5.0 date-fns: 4.4.0 react: 19.2.6 optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6): dependencies: @@ -20606,19 +19788,19 @@ snapshots: - bufferutil - utf-8-validate - react-dom@19.2.3(react@19.2.3): - dependencies: - react: 19.2.3 - scheduler: 0.27.0 - react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 scheduler: 0.27.0 - react-freeze@1.0.4(react@19.2.3): + react-dom@19.3.0(react@19.3.0): + dependencies: + react: 19.3.0 + scheduler: 0.28.0 + + react-freeze@1.0.4(react@19.3.0): dependencies: - react: 19.2.3 + react: 19.3.0 react-grab@0.1.44(react@19.2.6): dependencies: @@ -20627,19 +19809,17 @@ snapshots: optionalDependencies: react: 19.2.6 - react-is@16.13.1: {} - react-is@17.0.2: {} react-is@18.3.1: {} react-is@19.2.7: {} - react-markdown@10.1.0(@types/react@19.2.16)(react@19.2.6): + react-markdown@10.1.0(@types/react@19.3.0)(react@19.2.6): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@types/react': 19.2.16 + '@types/react': 19.3.0 devlop: 1.1.0 hast-util-to-jsx-runtime: 2.3.6 html-url-attributes: 3.0.1 @@ -20653,122 +19833,89 @@ snapshots: transitivePeerDependencies: - supports-color - react-native-gesture-handler@2.32.0(patch_hash=0579f8e4dad02bf3183d95b02620358412983c36f9bda7425dc8bcb9643b5ce2)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-gesture-handler@3.2.1(patch_hash=d518a937e3cb2df5e7d67f1ab6b265c74a8639e4572d1b032b7b747e9b1c01a9)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - '@egjs/hammerjs': 2.0.17 '@types/react-test-renderer': 19.1.0 - hoist-non-react-statics: 3.3.2 invariant: 2.2.4 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-image-viewing@0.2.2(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-image-viewing@0.2.2(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-is-edge-to-edge@1.3.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-is-edge-to-edge@1.3.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - ? react-native-keyboard-controller@1.21.13(patch_hash=6e4339347bc5bb3c9ea67d85ff5c814058b211c5750f247aba59d07869a2e787)(react-native-reanimated@4.5.5(patch_hash=bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - : dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-is-edge-to-edge: 1.3.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react-native-reanimated: 4.5.5(patch_hash=bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react-native-keyboard-controller@1.22.4(patch_hash=a438114039aed2e280a81d95c25723132ad071e4768fe492bd92aa628ad74597)(react-native-reanimated@4.7.0(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + dependencies: + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-is-edge-to-edge: 1.3.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react-native-reanimated: 4.7.0(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - react-native-nitro-markdown@0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-nitro-markdown@0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-nitro-modules: 0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-nitro-modules: 0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) optionalDependencies: - react-native-svg: 15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react-native-svg: 15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - react-native-nitro-modules@0.35.9(patch_hash=825622aae63a8fb5b904f3c77908a0e216261d727ea171709f2c0b6088422675)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-nitro-modules@0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-reanimated@4.5.5(patch_hash=bae9878a5bdba94e11c890e5ee164542feb622624fc81c13890063094608216d)(react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-reanimated@4.7.0(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - react-native-is-edge-to-edge: 1.3.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - react-native-worklets: 0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) + react-native-is-edge-to-edge: 1.3.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + react-native-worklets: 0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) semver: 7.8.5 - react-native-safe-area-context@5.7.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-safe-area-context@5.9.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-screens@4.26.2(patch_hash=595114f3f9ce8b9f0d99d1aafe5c12c997b7d75ca9add31d46cbedbfe347b8e0)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-screens@4.28.0(patch_hash=cc1301436ee62c39860acc9ee1a1e60b7d47e6abd211c42effa62c056d165483)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - react: 19.2.3 - react-freeze: 1.0.4(react@19.2.3) - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-freeze: 1.0.4(react@19.3.0) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) warn-once: 0.1.1 - react-native-shiki-engine@0.3.12(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-shiki-engine@0.3.12(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@shikijs/types': 4.3.0 '@shikijs/vscode-textmate': 10.0.2 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-svg@15.15.4(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: css-select: 5.2.2 css-tree: 1.1.3 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - warn-once: 0.1.1 - - react-native-url-polyfill@4.0.0(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6)): - dependencies: - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-webview@13.16.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-url-polyfill@4.0.0(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - escape-string-regexp: 4.0.0 - invariant: 2.2.4 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-webview@13.16.1(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6): + react-native-webview@14.0.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: escape-string-regexp: 4.0.0 invariant: 2.2.4 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - optional: true - - react-native-worklets@0.10.1(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6): - dependencies: - '@babel/core': 7.29.7 - '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7) - '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) - '@babel/types': 7.29.8 - '@react-native/metro-config': 0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6) - convert-source-map: 2.0.0 - react: 19.2.6 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6) - semver: 7.8.5 - transitivePeerDependencies: - - supports-color - optional: true + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - react-native-worklets@0.11.4(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3): + react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@babel/core': 7.29.7 '@babel/generator': 7.29.7 @@ -20782,89 +19929,43 @@ snapshots: '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7) '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - '@react-native/metro-config': 0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + '@react-native/metro-config': 0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6) convert-source-map: 2.0.0 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) - semver: 7.8.5 - transitivePeerDependencies: - - supports-color - - react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6): - dependencies: - '@react-native/assets-registry': 0.86.3 - '@react-native/codegen': 0.86.3(@babel/core@7.29.7) - '@react-native/community-cli-plugin': 0.86.3(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@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(@types/react@19.2.16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3) - abort-controller: 3.0.0 - anser: 1.4.10 - ansi-regex: 5.0.1 - babel-plugin-syntax-hermes-parser: 0.36.0 - base64-js: 1.5.1 - commander: 12.1.0 - flow-enums-runtime: 0.0.6 - hermes-compiler: 250829098.0.17 - invariant: 2.2.4 - memoize-one: 5.2.1 - metro-runtime: 0.84.4 - metro-source-map: 0.84.4 - nullthrows: 1.1.1 - pretty-format: 29.7.0 - promise: 8.3.0 - react: 19.2.3 - react-devtools-core: 6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - react-refresh: 0.14.2 - regenerator-runtime: 0.13.11 - scheduler: 0.27.0 + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) semver: 7.8.5 - stacktrace-parser: 0.1.11 - tinyglobby: 0.2.17 whatwg-fetch: 3.6.20 - ws: 7.5.11(bufferutil@4.1.0)(utf-8-validate@6.0.6) - yargs: 17.7.2 - optionalDependencies: - '@types/react': 19.2.16 transitivePeerDependencies: - - '@babel/core' - - '@react-native-community/cli' - - '@react-native/metro-config' - - bufferutil - supports-color - - utf-8-validate - react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6): + react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6): dependencies: - '@react-native/assets-registry': 0.86.3 - '@react-native/codegen': 0.86.3(@babel/core@7.29.7) - '@react-native/community-cli-plugin': 0.86.3(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@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(@types/react@19.2.16)(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.6)(utf-8-validate@6.0.6))(react@19.2.6) - abort-controller: 3.0.0 + '@react-native/asset-utils': 0.88.0-rc.3 + '@react-native/codegen': 0.88.0-rc.3(@babel/core@7.29.7) + '@react-native/community-cli-plugin': 0.88.0-rc.3(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@react-native/gradle-plugin': 0.88.0-rc.3 + '@react-native/normalize-colors': 0.88.0-rc.3 + '@react-native/virtualized-lists': 0.88.0-rc.3(@types/react@19.3.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) anser: 1.4.10 ansi-regex: 5.0.1 - babel-plugin-syntax-hermes-parser: 0.36.0 base64-js: 1.5.1 - commander: 12.1.0 flow-enums-runtime: 0.0.6 - hermes-compiler: 250829098.0.17 + flow-parser: 0.327.0 + hermes-compiler: 260318099.0.4 invariant: 2.2.4 memoize-one: 5.2.1 - metro-runtime: 0.84.4 - metro-source-map: 0.84.4 + 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: 19.2.6 + react: 19.3.0 react-devtools-core: 6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) react-refresh: 0.14.2 regenerator-runtime: 0.13.11 - scheduler: 0.27.0 + scheduler: 0.28.0 semver: 7.8.5 stacktrace-parser: 0.1.11 tinyglobby: 0.2.17 @@ -20872,7 +19973,7 @@ snapshots: ws: 7.5.11(bufferutil@4.1.0)(utf-8-validate@6.0.6) yargs: 17.7.2 optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 transitivePeerDependencies: - '@babel/core' - '@react-native-community/cli' @@ -20880,47 +19981,19 @@ snapshots: - bufferutil - supports-color - utf-8-validate - optional: true react-refresh@0.14.2: {} - react-remove-scroll-bar@2.3.8(@types/react@19.2.16)(react@19.2.3): - dependencies: - react: 19.2.3 - react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.3) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - react-remove-scroll@2.7.2(@types/react@19.2.16)(react@19.2.3): - dependencies: - react: 19.2.3 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.16)(react@19.2.3) - react-style-singleton: 2.2.3(@types/react@19.2.16)(react@19.2.3) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.16)(react@19.2.3) - use-sidecar: 1.1.3(@types/react@19.2.16)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.16 - - react-style-singleton@2.2.3(@types/react@19.2.16)(react@19.2.3): - dependencies: - get-nonce: 1.0.1 - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - react-test-renderer@19.2.6(react@19.2.6): dependencies: react: 19.2.6 react-is: 19.2.7 scheduler: 0.27.0 - react@19.2.3: {} - react@19.2.6: {} + react@19.3.0: {} + read-binary-file-arch@1.0.6: dependencies: debug: 4.4.3 @@ -21206,6 +20279,8 @@ snapshots: scheduler@0.27.0: {} + scheduler@0.28.0: {} + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 @@ -21874,20 +20949,20 @@ snapshots: universalify@2.0.1: {} - uniwind@1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.84.5)(metro-transform-worker@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6))(react@19.2.3)(tailwindcss@4.3.3): + uniwind@1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3): dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 culori: 4.0.2 lightningcss: 1.33.0 - metro: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) - metro-cache: 0.84.5 - react: 19.2.3 - react-native: 0.86.3(@babel/core@7.29.7)(@react-native/metro-config@0.86.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.2.16)(bufferutil@4.1.0)(react@19.2.3)(utf-8-validate@6.0.6) + metro: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) + metro-cache: 0.87.1 + react: 19.3.0 + react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) tailwindcss: 4.3.3 optionalDependencies: - '@expo/metro-config': 57.0.12(patch_hash=96f1a75347e6ea02dc4b7034ace815d8ee39e18b8166ebfb573d9e58328f0dc2)(bufferutil@4.1.0)(expo@57.0.18)(typescript@7.0.2)(utf-8-validate@6.0.6) - metro-transform-worker: 0.84.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + metro-transform-worker: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) unpipe@1.0.0: {} @@ -21939,33 +21014,18 @@ snapshots: punycode: 2.3.1 optional: true - use-callback-ref@1.3.3(@types/react@19.2.16)(react@19.2.3): - dependencies: - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - use-latest-callback@0.2.6(react@19.2.3): + use-latest-callback@0.2.6(react@19.3.0): dependencies: - react: 19.2.3 - - use-sidecar@1.1.3(@types/react@19.2.16)(react@19.2.3): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.3 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.16 - - use-sync-external-store@1.6.0(react@19.2.3): - dependencies: - react: 19.2.3 + react: 19.3.0 use-sync-external-store@1.6.0(react@19.2.6): dependencies: react: 19.2.6 + use-sync-external-store@1.6.0(react@19.3.0): + dependencies: + react: 19.3.0 + utf-8-validate@6.0.6: dependencies: node-gyp-build: 4.8.4 @@ -21988,15 +21048,6 @@ snapshots: vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.16))(@types/react@19.2.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 @@ -22235,7 +21286,7 @@ snapshots: whatwg-mimetype@5.0.0: {} - whatwg-url-minimum@0.1.2: {} + whatwg-url-minimum@0.2.0: {} whatwg-url@14.2.0: dependencies: @@ -22461,9 +21512,9 @@ snapshots: zod@4.6.5: {} - zustand@5.0.14(@types/react@19.2.16)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)): + zustand@5.0.14(@types/react@19.3.0)(react@19.2.6)(use-sync-external-store@1.6.0(react@19.2.6)): optionalDependencies: - '@types/react': 19.2.16 + '@types/react': 19.3.0 react: 19.2.6 use-sync-external-store: 1.6.0(react@19.2.6) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 590d808e2da0..9a887cb06045 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -54,6 +54,9 @@ catalog: yaml: ^2.9.0 minimumReleaseAgeExclude: + - expo-glass-effect@58.0.3 + - expo-blur@58.0.2 + - expo-audio@58.0.3 - "@clerk/backend@3.18.1" - "@clerk/clerk-js@6.32.1" - "@clerk/electron@0.0.44" @@ -75,15 +78,40 @@ minimumReleaseAgeExclude: - alchemy@2.0.0-beta.79 - effect@4.0.0-rc.115 - "@legendapp/list@3.3.5" - - "@expo/cli@57.0.20" - - "@expo/env@2.4.3" - - "@expo/fingerprint@0.20.11" - - "@expo/metro-config@57.0.12" - - expo-constants@57.0.16 - - expo-font@57.0.2 - - expo-updates@57.0.19 - - expo@57.0.18 - - expo-widgets@57.0.15 + - "@expo/cli@58.0.9" + - "@expo/env@2.5.1" + - "@expo/fingerprint@0.21.2" + - "@expo/metro-config@58.0.6" + - expo-constants@58.0.9 + - expo-font@58.0.4 + - expo-updates@58.0.11 + - expo@58.0.0 + - expo-widgets@58.0.9 + - "@expo/config-plugins@58.0.4" + - "@expo/log-box@58.0.7" + - "@expo/metro-file-map@58.0.3" + - "@expo/metro-runtime@58.0.9" + - "@expo/metro@58.0.0-rc.0" + - "@expo/prebuild-config@58.0.6" + - "@expo/router-server@58.0.4" + - "@expo/ui@58.0.9" + - babel-preset-expo@58.0.6 + - expo-asset@58.0.9 + - expo-build-properties@58.0.9 + - expo-dev-client@58.0.9 + - expo-dev-launcher@58.0.9 + - expo-dev-menu@58.0.9 + - expo-image-manipulator@58.0.10 + - expo-image-picker@58.0.9 + - expo-image@58.0.8 + - expo-linking@58.0.9 + - expo-modules-autolinking@58.0.6 + - expo-modules-core@58.0.9 + - expo-modules-jsi@58.0.5 + - expo-notifications@58.0.9 + - expo-sharing@58.0.12 + - expo-sqlite@58.0.7 + - expo-symbols@58.0.3 - electron@44.4.2 - "@anthropic-ai/claude-agent-sdk@0.3.276" - "@alchemy.run/cloudflare-runtime@2.0.0-beta.79" @@ -96,6 +124,29 @@ minimumReleaseAgeExclude: - "@distilled.cloud/stripe@1.0.0-rc.12" - "@shadcn/lint@0.1.5" - cn@0.3.2 + - "@expo/dom-webview@58.0.2" + - "expo-auth-session@58.0.6" + - "expo-camera@58.0.5" + - "expo-clipboard@58.0.2" + - "expo-crypto@58.0.3" + - "expo-device@58.0.3" + - "expo-document-picker@58.0.3" + - "expo-file-system@58.0.4" + - "expo-haptics@58.0.3" + - "expo-keep-awake@58.0.2" + - "expo-network@58.0.2" + - "expo-secure-store@58.0.1" + - "expo-splash-screen@58.0.2" + - "expo-video@58.0.5" + - "expo-web-browser@58.0.3" + - "react@19.3.0" + - "react-dom@19.3.0" + - "react-native@0.88.0-rc.3" + - "react-native-keyboard-controller@1.22.4" + - "react-native-worklets@0.13.0" + - "react-native-reanimated@4.7.0" + - "react-native-screens@4.28.0" + - "@expo/config-types@58.0.2" overrides: # Keep jsdom's optional peer consistent so Vite+ has one test-runner instance. @@ -143,11 +194,12 @@ overrides: "@effect/sql-pg": "catalog:" "@effect/vitest": "catalog:" "@effect/vitest>vitest": "-" - "@expo/dom-webview": 57.0.1 - "@expo/metro-config": 57.0.12 - expo-constants: 57.0.16 - # Keep fresh resolution on the version carrying the permissions registry fix. - expo-modules-core: 57.0.14 + "@expo/dom-webview": 58.0.2 + "@expo/metro-config": 58.0.6 + expo-constants: 58.0.9 + expo-router: 58.0.10 + "expo-sharing>@expo/config-plugins": 58.0.4 + "expo-sharing>@expo/config-types": 58.0.2 "@pierre/diffs>@shikijs/transformers": ^4.2.0 # Keep one copy of these native-binary packages. lightningcss ships 11 platform binaries per # version, and the workspaces' tailwindcss ^4 ranges drift into two 4.3.x copies of the family. @@ -156,9 +208,6 @@ overrides: "@tailwindcss/vite": "catalog:" "@types/node": "catalog:" effect: "catalog:" - expo-router: 57.0.17 - "expo-sharing>@expo/config-plugins": 57.0.9 - "expo-sharing>@expo/config-types": 57.0.2 node-abi: 4.33.0 lightningcss: "catalog:" tailwindcss: "catalog:" @@ -168,7 +217,7 @@ overrides: packageExtensions: "@clerk/expo@*": dependencies: - "@expo/config-plugins": 57.0.9 + "@expo/config-plugins": 58.0.4 "@effect/vitest@*": dependencies: vite-plus: "catalog:" @@ -181,9 +230,14 @@ packageExtensions: patchedDependencies: alchemy@2.0.0-beta.79: patches/alchemy@2.0.0-beta.79.patch + expo-glass-effect@58.0.3: patches/expo-glass-effect@58.0.3.patch + expo-blur@58.0.2: patches/expo-blur@58.0.2.patch + expo-audio@58.0.3: patches/expo-audio@58.0.3.patch "@clerk/expo@4.6.8": patches/@clerk__expo@4.6.8.patch "@effect/vitest@4.0.0-rc.115": patches/@effect__vitest@4.0.0-rc.115.patch - "@expo/metro-config@57.0.12": patches/@expo__metro-config@57.0.12.patch + "@expo/metro-config@58.0.6": patches/@expo__metro-config@58.0.6.patch + expo-sharing@58.0.12: patches/expo-sharing@58.0.12.patch + expo-widgets@58.0.9: patches/expo-widgets@58.0.9.patch "@ff-labs/fff-node@0.9.4": patches/@ff-labs__fff-node@0.9.4.patch "@legendapp/list@3.3.5": patches/@legendapp__list@3.3.5.patch "@pierre/diffs@1.3.0-beta.10": patches/@pierre%2Fdiffs@1.3.0-beta.10.patch @@ -192,20 +246,13 @@ patchedDependencies: "@react-navigation/native-stack@7.17.6": patches/@react-navigation%2Fnative-stack@7.17.6.patch dbus-next@0.10.2: patches/dbus-next@0.10.2.patch effect@4.0.0-rc.115: patches/effect@4.0.0-rc.115.patch - expo-audio@57.0.4: patches/expo-audio@57.0.4.patch - expo-modules-core@57.0.14: patches/expo-modules-core@57.0.14.patch - expo-notifications@57.0.15: patches/expo-notifications@57.0.15.patch - expo-sharing@57.0.17: patches/expo-sharing@57.0.17.patch - expo-widgets@57.0.15: patches/expo-widgets@57.0.15.patch node-pty@1.2.0-beta.15: patches/node-pty@1.2.0-beta.15.patch - react-native-gesture-handler@2.32.0: patches/react-native-gesture-handler@2.32.0.patch - react-native-keyboard-controller@1.21.13: patches/react-native-keyboard-controller@1.21.13.patch - react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch # Link http(s) URLs with a port or a single-label host. md4c otherwise requires a dotted host and stops at ':'. react-native-nitro-markdown@0.5.8: patches/react-native-nitro-markdown@0.5.8.patch - # Preserve the final layout frame. Backport of [#10171](https://github.com/software-mansion/react-native-reanimated/pull/10171). - react-native-reanimated@4.5.5: patches/react-native-reanimated@4.5.5.patch - react-native-screens@4.26.2: patches/react-native-screens@4.26.2.patch + react-native-gesture-handler@3.2.1: patches/react-native-gesture-handler@3.2.1.patch + react-native-keyboard-controller@1.22.4: patches/react-native-keyboard-controller@1.22.4.patch + react-native-nitro-modules@0.35.9: patches/react-native-nitro-modules@0.35.9.patch + react-native-screens@4.28.0: patches/react-native-screens@4.28.0.patch uniwind@1.11.0: patches/uniwind@1.11.0.patch peerDependencyRules: diff --git a/third-party-licenses.config.json b/third-party-licenses.config.json index 5c7c35f13b46..aaa5413c3ace 100644 --- a/third-party-licenses.config.json +++ b/third-party-licenses.config.json @@ -473,6 +473,87 @@ "licenseId": "MIT", "copyrights": ["Copyright (c) 2025 opencode"] } + }, + { + "license": "MIT", + "name": "noxcturnal", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-linux-x64-gnu", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-darwin-x64", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-linux-arm64-gnu", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-darwin-arm64", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-linux-arm64-musl", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-linux-x64-musl", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-win32-arm64-msvc", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } + }, + { + "license": "MIT", + "name": "@noxcturnal/noxcturnal-win32-x64-msvc", + "sourceUrl": "https://github.com/expo/noxcturnal", + "generatedNotice": { + "licenseId": "MIT", + "copyrights": ["Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)"] + } } ] } From e41755cf8a9b07a12fefee5134cadacb514d4ad9 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:23 -0700 Subject: [PATCH 03/32] feat(mobile): render the Android subscription widget with expo-widgets (#12046) Co-authored-by: Claude Fable 5 --- apps/mobile/app.config.ts | 79 ++++---- .../android/build.gradle | 18 -- .../android/src/main/AndroidManifest.xml | 8 - .../SubscriptionUsageWidget.kt | 174 ------------------ .../T3SubscriptionWidgetModule.kt | 18 -- .../t3_subscription_widget_background.xml | 4 - .../res/layout/t3_subscription_widget.xml | 10 - .../res/layout/t3_subscription_widget_row.xml | 10 - .../src/main/res/values-night/colors.xml | 5 - .../android/src/main/res/values/colors.xml | 5 - .../android/src/main/res/values/strings.xml | 15 -- .../res/xml/t3_subscription_widget_info.xml | 9 - .../expo-module.config.json | 4 - .../t3-widget-expiry/android/build.gradle | 29 +++ .../android/src/main/AndroidManifest.xml | 10 + .../t3widgetexpiry/T3WidgetExpiryModule.kt | 14 ++ .../t3widgetexpiry/WidgetExpiryReceiver.kt | 82 +++++++++ .../WidgetExpiryReceiverTest.kt | 58 ++++++ .../t3-widget-expiry/expo-module.config.json | 4 + .../widgets/SubscriptionUsage.android.test.ts | 93 ++++++++++ .../src/widgets/SubscriptionUsage.android.tsx | 114 ++++++++++++ .../publishSubscriptionUsage.android.ts | 33 +++- docs/user/usage.md | 6 +- 23 files changed, 483 insertions(+), 319 deletions(-) delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/build.gradle delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/AndroidManifest.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/SubscriptionUsageWidget.kt delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/T3SubscriptionWidgetModule.kt delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/drawable/t3_subscription_widget_background.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget_row.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/values-night/colors.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/colors.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/strings.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/android/src/main/res/xml/t3_subscription_widget_info.xml delete mode 100644 apps/mobile/modules/t3-subscription-widget/expo-module.config.json create mode 100644 apps/mobile/modules/t3-widget-expiry/android/build.gradle create mode 100644 apps/mobile/modules/t3-widget-expiry/android/src/main/AndroidManifest.xml create mode 100644 apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/T3WidgetExpiryModule.kt create mode 100644 apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiver.kt create mode 100644 apps/mobile/modules/t3-widget-expiry/android/src/test/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiverTest.kt create mode 100644 apps/mobile/modules/t3-widget-expiry/expo-module.config.json create mode 100644 apps/mobile/src/widgets/SubscriptionUsage.android.test.ts create mode 100644 apps/mobile/src/widgets/SubscriptionUsage.android.tsx diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index 6a992e6c5264..a1ab75b89fc2 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -129,51 +129,66 @@ const widgetsPlugin: NonNullable[number] = [ // Agent activity can update many times an hour; without the // frequent-updates entitlement iOS throttles the update budget sooner. frequentUpdates: true, + enableAndroid: true, widgets: [ { name: "SubscriptionUsage", displayName: "Subscription usage", description: "Subscription quotas from your connected T3 Code environments.", - configuration: { - title: "Subscription usage", - description: - "Both shows Session and Weekly when available. The Lock Screen shows the tightest selected limit.", - parameters: { - codexPeriod: { - title: "Codex limits", - type: "enum", - default: "auto", - values: [ - { name: "Both", value: "auto" }, - { name: "Session", value: "session" }, - { name: "Weekly", value: "weekly" }, - ], - }, - claudePeriod: { - title: "Claude limits", - type: "enum", - default: "auto", - values: [ - { name: "Both", value: "auto" }, - { name: "Session", value: "session" }, - { name: "Weekly", value: "weekly" }, - ], + ios: { + configuration: { + title: "Subscription usage", + description: + "Both shows Session and Weekly when available. The Lock Screen shows the tightest selected limit.", + parameters: { + codexPeriod: { + title: "Codex limits", + type: "enum", + default: "auto", + values: [ + { name: "Both", value: "auto" }, + { name: "Session", value: "session" }, + { name: "Weekly", value: "weekly" }, + ], + }, + claudePeriod: { + title: "Claude limits", + type: "enum", + default: "auto", + values: [ + { name: "Both", value: "auto" }, + { name: "Session", value: "session" }, + { name: "Weekly", value: "weekly" }, + ], + }, }, }, + supportedFamilies: [ + "systemSmall", + "systemMedium", + "systemLarge", + "systemExtraLarge", + "accessoryRectangular", + ], + }, + android: { + minWidth: 250, + minHeight: 180, + targetCellWidth: 4, + targetCellHeight: 3, + resizeMode: "both", + // Embeds the layout in the APK so the widget renders before the app + // has run once; the app replaces it with stored props on publish. + initialLayout: "./src/widgets/SubscriptionUsage.android.tsx", }, - supportedFamilies: [ - "systemSmall", - "systemMedium", - "systemLarge", - "systemExtraLarge", - "accessoryRectangular", - ], }, { name: "AgentActivity", displayName: "Agent Activity", description: "Shows the current state of active T3 Code agents.", - supportedFamilies: ["systemSmall", "systemMedium", "accessoryRectangular"], + // Live Activity companion; there is no Android presentation for it. + android: null, + ios: { supportedFamilies: ["systemSmall", "systemMedium", "accessoryRectangular"] }, }, ], }, diff --git a/apps/mobile/modules/t3-subscription-widget/android/build.gradle b/apps/mobile/modules/t3-subscription-widget/android/build.gradle deleted file mode 100644 index 7de5052417c0..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'org.jetbrains.kotlin.android' - -group = 'com.t3tools.subscriptionwidget' -version = '0.0.0' - -android { - namespace 'expo.modules.t3subscriptionwidget' - compileSdk rootProject.ext.compileSdkVersion - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - } -} - -dependencies { - implementation project(':expo-modules-core') -} diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/AndroidManifest.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/AndroidManifest.xml deleted file mode 100644 index e98c1ad6b312..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/SubscriptionUsageWidget.kt b/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/SubscriptionUsageWidget.kt deleted file mode 100644 index b8a916129ea7..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/SubscriptionUsageWidget.kt +++ /dev/null @@ -1,174 +0,0 @@ -package expo.modules.t3subscriptionwidget - -import android.app.AlarmManager -import android.app.PendingIntent -import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProvider -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.view.View -import android.widget.RemoteViews -import org.json.JSONObject -import java.text.DateFormat -import java.util.Date - -class SubscriptionUsageWidget : AppWidgetProvider() { - override fun onUpdate(context: Context, manager: AppWidgetManager, ids: IntArray) { - ids.forEach { update(context, manager, it) } - } - - override fun onReceive(context: Context, intent: Intent) { - super.onReceive(context, intent) - if (intent.action == EXPIRE) updateAll(context) - } - - override fun onDisabled(context: Context) { - context.getSystemService(AlarmManager::class.java).cancel(expiryIntent(context)) - } - - companion object { - const val PREFERENCES = "t3_subscription_widget" - private const val EXPIRE = "expo.modules.t3subscriptionwidget.EXPIRE" - - private fun expiryIntent(context: Context): PendingIntent = PendingIntent.getBroadcast( - context, - 0, - Intent(context, SubscriptionUsageWidget::class.java).setAction(EXPIRE), - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - ) - - fun updateAll(context: Context) { - val manager = AppWidgetManager.getInstance(context) - manager.getAppWidgetIds(ComponentName(context, SubscriptionUsageWidget::class.java)) - .forEach { update(context, manager, it) } - } - - private fun update(context: Context, manager: AppWidgetManager, id: Int) { - // The receiver is disabled below 12L (values-v32/bools.xml), but the module still calls in. - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S_V2) return - val saved = context.getSharedPreferences(PREFERENCES, 0).getString("snapshot", null) - val snapshot = runCatching { JSONObject(saved.orEmpty()) }.getOrNull() - val openApp = openAppIntent(context, id, snapshot) - val providers = snapshot?.optJSONArray("providers") - val now = System.currentTimeMillis() - var nextExpiry = Long.MAX_VALUE - val groups = (0 until (providers?.length() ?: 0)).mapNotNull { index -> - val provider = providers?.optJSONObject(index) ?: return@mapNotNull null - val windows = provider.optJSONArray("windows") - val expiresAt = provider.optLong("expiresAt") - if (expiresAt > now && windows != null && windows.length() > 0) { - nextExpiry = minOf(nextExpiry, expiresAt) - (0 until windows.length()).map { provider to windows.optJSONObject(it) } - } else { - listOf(provider to null) - } - } - // Keep the first quota from each provider near the top of the list. - val rows = (0 until (groups.maxOfOrNull { it.size } ?: 0)).flatMap { index -> - groups.mapNotNull { it.getOrNull(index) } - } - val views = RemoteViews(context.packageName, R.layout.t3_subscription_widget) - // Count limits only; "Open app to refresh" placeholders are not entries. - val limits = rows.count { (_, window) -> window != null } - // Without limits the layout's plain title stays. - if (limits > 0) { - views.setTextViewText( - R.id.t3_widget_title, - context.getString(R.string.t3_subscription_widget_title_count, limits) - ) - views.setContentDescription( - R.id.t3_widget_title, - context.resources.getQuantityString( - R.plurals.t3_subscription_widget_title_description, - limits, - limits - ) - ) - } - openApp?.let { views.setOnClickPendingIntent(R.id.t3_widget_root, it) } - openAppIntent(context, id, snapshot, forCollection = true)?.let { - views.setPendingIntentTemplate(R.id.t3_widget_rows, it) - } - val items = RemoteViews.RemoteCollectionItems.Builder() - rows.forEachIndexed { index, (provider, window) -> - items.addItem(index.toLong(), rowView(context, provider, window)) - } - views.setRemoteAdapter(R.id.t3_widget_rows, items.build()) - views.setEmptyView(R.id.t3_widget_rows, R.id.t3_widget_empty) - val checkedAt = snapshot?.optLong("checkedAt") ?: 0 - val checked = if (checkedAt > 0) { - val formatted = DateFormat.getDateTimeInstance( - DateFormat.SHORT, - DateFormat.SHORT - ).format(Date(checkedAt)) - context.getString(R.string.t3_subscription_widget_last_checked, formatted) - } else { - context.getString(R.string.t3_subscription_widget_unknown_check) - } - views.setTextViewText(R.id.t3_widget_footer, checked) - val alarms = context.getSystemService(AlarmManager::class.java) - alarms.cancel(expiryIntent(context)) - // Inexact and non-wakeup: the timestamp remains visible if Android delays expiry. - if (nextExpiry != Long.MAX_VALUE) { - alarms.set(AlarmManager.RTC, nextExpiry, expiryIntent(context)) - } - manager.updateAppWidget(id, views) - } - - private fun openAppIntent( - context: Context, - id: Int, - snapshot: JSONObject?, - forCollection: Boolean = false - ): PendingIntent? { - // Target this variant's launcher so co-installed builds cannot steal the tap. - val intent = - context.packageManager.getLaunchIntentForPackage(context.packageName) ?: return null - intent.action = Intent.ACTION_VIEW - val deepLink = snapshot?.optString("url")?.takeIf { it.isNotBlank() } - ?: "t3code://settings/usage?tab=limits" - intent.data = Uri.parse(deepLink) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP - return PendingIntent.getActivity( - context, - id * 2 + if (forCollection) 1 else 0, - intent, - PendingIntent.FLAG_UPDATE_CURRENT or if (forCollection) { - // Collection rows use fill-in intents with an explicit app target. - PendingIntent.FLAG_MUTABLE - } else { - PendingIntent.FLAG_IMMUTABLE - } - ) - } - - private fun rowView(context: Context, provider: JSONObject, window: JSONObject?): RemoteViews { - val child = RemoteViews(context.packageName, R.layout.t3_subscription_widget_row) - val remaining = window?.optInt("remaining")?.coerceIn(0, 100) - val detail = provider.optString("detail") - val label = provider.optString("name") - val windowLabel = window?.optString("label") ?: detail - child.setTextViewText(R.id.t3_widget_label, label) - child.setTextViewText(R.id.t3_widget_window, windowLabel) - val percent = remaining?.let { - context.getString(R.string.t3_subscription_widget_remaining, it) - } ?: "—" - child.setTextViewText(R.id.t3_widget_percent, percent) - val visibility = if (remaining == null) View.GONE else View.VISIBLE - child.setViewVisibility(R.id.t3_widget_progress, visibility) - if (remaining != null) child.setProgressBar(R.id.t3_widget_progress, 100, remaining, false) - val reset = window?.optString("reset") - ?: context.getString(R.string.t3_subscription_widget_refresh) - child.setTextViewText(R.id.t3_widget_reset, reset) - child.setOnClickFillInIntent(R.id.t3_widget_row, Intent()) - child.setContentDescription( - R.id.t3_widget_row, - "$label. $windowLabel. $percent. $reset. $detail" - ) - return child - } - } -} diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/T3SubscriptionWidgetModule.kt b/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/T3SubscriptionWidgetModule.kt deleted file mode 100644 index 6557b70958de..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/java/expo/modules/t3subscriptionwidget/T3SubscriptionWidgetModule.kt +++ /dev/null @@ -1,18 +0,0 @@ -package expo.modules.t3subscriptionwidget - -import expo.modules.kotlin.modules.Module -import expo.modules.kotlin.modules.ModuleDefinition -import org.json.JSONObject - -class T3SubscriptionWidgetModule : Module() { - override fun definition() = ModuleDefinition { - Name("T3SubscriptionWidget") - Function("updateSnapshot") { snapshot: String -> - val context = appContext.reactContext ?: return@Function - JSONObject(snapshot) // Reject malformed writes before replacing the saved snapshot. - context.getSharedPreferences(SubscriptionUsageWidget.PREFERENCES, 0) - .edit().putString("snapshot", snapshot).apply() - SubscriptionUsageWidget.updateAll(context) - } - } -} diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/drawable/t3_subscription_widget_background.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/drawable/t3_subscription_widget_background.xml deleted file mode 100644 index 69ec028ee8af..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/drawable/t3_subscription_widget_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget.xml deleted file mode 100644 index bf800d249fe0..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget_row.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget_row.xml deleted file mode 100644 index 941f27ef856a..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/layout/t3_subscription_widget_row.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values-night/colors.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values-night/colors.xml deleted file mode 100644 index 0647eb1a8ea7..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values-night/colors.xml +++ /dev/null @@ -1,5 +0,0 @@ - - #18181B - #FAFAFA - #A1A1AA - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/colors.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/colors.xml deleted file mode 100644 index bf4ca10ecfc4..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/colors.xml +++ /dev/null @@ -1,5 +0,0 @@ - - #FAFAFA - #18181B - #52525B - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/strings.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/strings.xml deleted file mode 100644 index 586b82595345..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/values/strings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - Last checked unavailable - Subscription usage - Subscription usage (%1$d) - - Subscription usage, %1$d entry - Subscription usage, %1$d entries - - Saved subscription quotas from your T3 Code environments. Tap to refresh in the app. - No subscription limits available. Open T3 Code to connect. - Tap to open Usage - Open app to refresh - %1$d%% remaining - Last checked %1$s - diff --git a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/xml/t3_subscription_widget_info.xml b/apps/mobile/modules/t3-subscription-widget/android/src/main/res/xml/t3_subscription_widget_info.xml deleted file mode 100644 index 4dfdad5b0fec..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/android/src/main/res/xml/t3_subscription_widget_info.xml +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/apps/mobile/modules/t3-subscription-widget/expo-module.config.json b/apps/mobile/modules/t3-subscription-widget/expo-module.config.json deleted file mode 100644 index 7ddc9c09e221..000000000000 --- a/apps/mobile/modules/t3-subscription-widget/expo-module.config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "platforms": ["android"], - "android": { "modules": ["expo.modules.t3subscriptionwidget.T3SubscriptionWidgetModule"] } -} diff --git a/apps/mobile/modules/t3-widget-expiry/android/build.gradle b/apps/mobile/modules/t3-widget-expiry/android/build.gradle new file mode 100644 index 000000000000..86e73074b5d1 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/android/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.library' +apply plugin: 'org.jetbrains.kotlin.android' + +group = 'com.t3tools.widgetexpiry' +version = '0.0.0' + +android { + namespace 'expo.modules.t3widgetexpiry' + compileSdk rootProject.ext.compileSdkVersion + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + } + testOptions { + unitTests.includeAndroidResources = true + } +} + +dependencies { + implementation project(':expo-modules-core') + testImplementation 'junit:junit:4.13.2' + testImplementation 'org.robolectric:robolectric:4.16.1' +} + +tasks.withType(Test).configureEach { + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(21) + } +} diff --git a/apps/mobile/modules/t3-widget-expiry/android/src/main/AndroidManifest.xml b/apps/mobile/modules/t3-widget-expiry/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..9ae263ac37b1 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/android/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/T3WidgetExpiryModule.kt b/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/T3WidgetExpiryModule.kt new file mode 100644 index 000000000000..c9a2e4a440f1 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/T3WidgetExpiryModule.kt @@ -0,0 +1,14 @@ +package expo.modules.t3widgetexpiry + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition + +class T3WidgetExpiryModule : Module() { + override fun definition() = ModuleDefinition { + Name("T3WidgetExpiry") + Function("schedule") { name: String, deadlines: List -> + val context = appContext.reactContext ?: return@Function + WidgetExpiryReceiver.schedule(context, name, deadlines.map { it.toLong() }.toLongArray()) + } + } +} diff --git a/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiver.kt b/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiver.kt new file mode 100644 index 000000000000..2167b3beef30 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/android/src/main/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiver.kt @@ -0,0 +1,82 @@ +package expo.modules.t3widgetexpiry + +import android.app.AlarmManager +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent + +/** + * Re-renders an expo-widgets widget when a snapshot deadline passes while the app is closed. + * The generated `.Provider` receiver re-runs the JS layout with the stored + * snapshot on ACTION_APPWIDGET_UPDATE, so a deadline only needs to deliver that broadcast. + */ +class WidgetExpiryReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action == Intent.ACTION_BOOT_COMPLETED) { + val stored = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE) + for ((name, value) in stored.all) { + val deadlines = (value as? String)?.split(',')?.mapNotNull { it.toLongOrNull() } + ?.toLongArray() ?: continue + refresh(context, name) + schedule(context, name, deadlines) + } + return + } + val name = intent.getStringExtra(EXTRA_NAME) ?: return + val remaining = intent.getLongArrayExtra(EXTRA_DEADLINES) ?: LongArray(0) + refresh(context, name) + schedule(context, name, remaining) + } + + private fun refresh(context: Context, name: String) { + val provider = providerComponent(context, name) + val ids = AppWidgetManager.getInstance(context).getAppWidgetIds(provider) + if (ids.isNotEmpty()) { + context.sendBroadcast( + Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE) + .setComponent(provider) + .putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids) + ) + } + } + + companion object { + private const val EXTRA_NAME = "expo.modules.t3widgetexpiry.NAME" + private const val EXTRA_DEADLINES = "expo.modules.t3widgetexpiry.DEADLINES" + private const val PREFERENCES = "expo.modules.t3widgetexpiry.DEADLINES" + + /** Arms one inexact, non-wakeup alarm for the next future deadline and carries the rest. */ + fun schedule(context: Context, name: String, deadlines: LongArray) { + val alarms = context.getSystemService(AlarmManager::class.java) + val now = System.currentTimeMillis() + val pending = deadlines.filter { it > now }.sorted() + val stored = context.getSharedPreferences(PREFERENCES, Context.MODE_PRIVATE).edit() + if (pending.isEmpty()) { + stored.remove(name) + } else { + stored.putString(name, pending.joinToString(",")) + } + stored.apply() + val intent = Intent(context, WidgetExpiryReceiver::class.java) + .setAction("expo.modules.t3widgetexpiry.EXPIRE.$name") + .putExtra(EXTRA_NAME, name) + .putExtra(EXTRA_DEADLINES, pending.drop(1).toLongArray()) + val operation = PendingIntent.getBroadcast( + context, + 0, + intent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + ) + alarms.cancel(operation) + val next = pending.firstOrNull() ?: return + alarms.set(AlarmManager.RTC, next, operation) + } + + // Mirrors expo-widgets' widgetProviderComponentName for the generated provider class. + private fun providerComponent(context: Context, name: String) = + ComponentName(context.packageName, "${context.packageName}.${name}Provider") + } +} diff --git a/apps/mobile/modules/t3-widget-expiry/android/src/test/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiverTest.kt b/apps/mobile/modules/t3-widget-expiry/android/src/test/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiverTest.kt new file mode 100644 index 000000000000..b63a2e915195 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/android/src/test/java/expo/modules/t3widgetexpiry/WidgetExpiryReceiverTest.kt @@ -0,0 +1,58 @@ +package expo.modules.t3widgetexpiry + +import android.app.AlarmManager +import android.content.Context +import android.content.Intent +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.Shadows.shadowOf +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [24, 36], manifest = Config.NONE) +class WidgetExpiryReceiverTest { + @Test + fun bootRestoresTheNextAlarmFromPersistedDeadlines() { + val context = RuntimeEnvironment.getApplication() + val alarms = context.getSystemService(AlarmManager::class.java) + val deadlines = longArrayOf( + System.currentTimeMillis() + 60000, + System.currentTimeMillis() + 120000 + ) + WidgetExpiryReceiver.schedule(context, "SubscriptionUsage", deadlines) + val scheduled = shadowOf(alarms).scheduledAlarms.single() + alarms.cancel(requireNotNull(scheduled.operation)) + assertTrue(shadowOf(alarms).scheduledAlarms.isEmpty()) + + WidgetExpiryReceiver().onReceive(context, Intent(Intent.ACTION_BOOT_COMPLETED)) + + assertEquals(deadlines[0], shadowOf(alarms).scheduledAlarms.single().triggerAtTime) + } + + @Test + fun bootDoesNotRestoreCancelledDeadlines() { + val context = RuntimeEnvironment.getApplication() + WidgetExpiryReceiver.schedule( + context, + "SubscriptionUsage", + longArrayOf(System.currentTimeMillis() + 60000) + ) + WidgetExpiryReceiver.schedule(context, "SubscriptionUsage", longArrayOf()) + + WidgetExpiryReceiver().onReceive(context, Intent(Intent.ACTION_BOOT_COMPLETED)) + + assertTrue( + shadowOf(context.getSystemService(AlarmManager::class.java)).scheduledAlarms.isEmpty() + ) + assertTrue( + context.getSharedPreferences( + "expo.modules.t3widgetexpiry.DEADLINES", + Context.MODE_PRIVATE + ).all.isEmpty() + ) + } +} diff --git a/apps/mobile/modules/t3-widget-expiry/expo-module.config.json b/apps/mobile/modules/t3-widget-expiry/expo-module.config.json new file mode 100644 index 000000000000..7bed9ce05433 --- /dev/null +++ b/apps/mobile/modules/t3-widget-expiry/expo-module.config.json @@ -0,0 +1,4 @@ +{ + "platforms": ["android"], + "android": { "modules": ["expo.modules.t3widgetexpiry.T3WidgetExpiryModule"] } +} diff --git a/apps/mobile/src/widgets/SubscriptionUsage.android.test.ts b/apps/mobile/src/widgets/SubscriptionUsage.android.test.ts new file mode 100644 index 000000000000..db2efd5da17b --- /dev/null +++ b/apps/mobile/src/widgets/SubscriptionUsage.android.test.ts @@ -0,0 +1,93 @@ +import { describe, expect, it, vi } from "vite-plus/test"; + +vi.mock("@expo/ui/jetpack-compose", () => ({ + Button: "Button", + Column: "Column", + LinearProgressIndicator: "LinearProgressIndicator", + Text: "Text", + getMaterialColors: ({ scheme }: { scheme: string }) => ({ + surface: `${scheme}-surface`, + onSurface: `${scheme}-onSurface`, + onSurfaceVariant: `${scheme}-onSurfaceVariant`, + surfaceVariant: `${scheme}-surfaceVariant`, + primary: `${scheme}-primary`, + error: `${scheme}-error`, + }), +})); + +vi.mock("@expo/ui/jetpack-compose/modifiers", () => ({ + fillMaxSize: () => "fillMaxSize", + fillMaxWidth: () => "fillMaxWidth", + height: (value: number) => ({ height: value }), + padding: (...values: number[]) => ({ padding: values }), + paddingAll: (value: number) => ({ paddingAll: value }), +})); + +vi.mock("expo-widgets", () => ({ + createWidget: vi.fn((name: string, layout: unknown) => ({ layout, name })), +})); + +import { SubscriptionUsage } from "./SubscriptionUsage.android"; +import type { SubscriptionUsageSnapshot } from "./subscriptionUsageSnapshot"; + +const now = Date.parse("2026-09-05T12:00:00.000Z"); +const provider = { + name: "Codex", + detail: "Subscription remaining", + windows: [ + { kind: "session", label: "5 hours", remaining: 60, reset: "Next reset Sep 5, 5:00 PM" }, + { kind: "weekly", label: "Weekly", remaining: 8, reset: "Next reset Sep 9, 9:00 AM" }, + ], + expiresAt: now + 60_000, + totalWindows: 2, +} satisfies SubscriptionUsageSnapshot["providers"][number]; +const snapshot = { + checkedAt: now, + url: "t3code-dev://settings/usage?tab=limits", + providers: [provider, { ...provider, name: "Claude" }], +} satisfies SubscriptionUsageSnapshot; + +function render(props: SubscriptionUsageSnapshot, colorScheme: "light" | "dark" = "dark") { + vi.setSystemTime(now); + return JSON.stringify(SubscriptionUsage(props, { colorScheme, configuration: undefined })); +} + +describe("SubscriptionUsage Android layout", () => { + it("renders each window with its remaining share, bar, and reset", () => { + const tree = render(snapshot); + expect(tree).toContain("5 hours · 60% left"); + expect(tree).toContain('"progress":0.6'); + expect(tree).toContain("Next reset Sep 5, 5:00 PM"); + expect(tree).toContain('"progress":0.08'); + expect(tree).toContain('"color":"dark-error"'); + expect(tree).toContain("As of "); + }); + + it("drops the bars and asks for a refresh once the snapshot expires", () => { + const tree = render({ + ...snapshot, + providers: [{ ...provider, expiresAt: now - 1 }], + }); + expect(tree).toContain("Open T3 to refresh"); + expect(tree).not.toContain("LinearProgressIndicator"); + expect(tree).not.toContain("more in T3"); + }); + + it("counts the quotas that did not fit", () => { + const tree = render({ ...snapshot, providers: [{ ...provider, totalWindows: 5 }] }); + expect(tree).toContain("3 more in T3"); + }); + + it("keeps quotas without an expiry deadline visible", () => { + const tree = render({ ...snapshot, providers: [{ ...provider, expiresAt: 0 }] }); + expect(tree).toContain("5 hours · 60% left"); + expect(tree).not.toContain("Open T3 to refresh"); + }); + + it("invites connecting when nothing has been checked", () => { + const tree = render({ checkedAt: 0, providers: [] }, "light"); + expect(tree).toContain("Tap to connect in T3"); + expect(tree).not.toContain("As of "); + expect(tree).toContain('"containerColor":"light-surface"'); + }); +}); diff --git a/apps/mobile/src/widgets/SubscriptionUsage.android.tsx b/apps/mobile/src/widgets/SubscriptionUsage.android.tsx new file mode 100644 index 000000000000..ac47edf8cdd1 --- /dev/null +++ b/apps/mobile/src/widgets/SubscriptionUsage.android.tsx @@ -0,0 +1,114 @@ +import { + Button, + Column, + getMaterialColors, + LinearProgressIndicator, + Text, +} from "@expo/ui/jetpack-compose"; +import { + fillMaxSize, + fillMaxWidth, + height, + padding, + paddingAll, +} from "@expo/ui/jetpack-compose/modifiers"; +import { createWidget, type WidgetEnvironment } from "expo-widgets"; + +import type { SubscriptionUsageSnapshot as SubscriptionUsageProps } from "./subscriptionUsageSnapshot"; + +export function SubscriptionUsage(props: SubscriptionUsageProps, environment: WidgetEnvironment) { + "widget"; + // The widget runtime evaluates this function without the app's module scope. + // Android has no timeline, so freshness is decided on every render; the + // expiry alarm and each tap trigger one while the app is closed. + const now = Date.now(); + // The 4x3 default cell fits two quotas per provider with their reset text. + const limit = 2; + const colors = getMaterialColors({ + scheme: environment.colorScheme === "dark" ? "dark" : "light", + }); + const muted = colors.onSurfaceVariant; + const providers = props.providers ?? [ + { name: "Codex", detail: "Open T3 to connect", windows: [], expiresAt: 0, totalWindows: 0 }, + { name: "Claude", detail: "Open T3 to connect", windows: [], expiresAt: 0, totalWindows: 0 }, + ]; + return ( + // The card is one Button so a tap reaches the app's interaction listener, + // which opens props.url. expo-widgets has no Android counterpart to widgetURL. + + ); +} + +export default createWidget("SubscriptionUsage", SubscriptionUsage); diff --git a/apps/mobile/src/widgets/publishSubscriptionUsage.android.ts b/apps/mobile/src/widgets/publishSubscriptionUsage.android.ts index a37b4f61eca3..406772d3d530 100644 --- a/apps/mobile/src/widgets/publishSubscriptionUsage.android.ts +++ b/apps/mobile/src/widgets/publishSubscriptionUsage.android.ts @@ -1,8 +1,33 @@ import { requireOptionalNativeModule } from "expo"; +import * as Linking from "expo-linking"; import type { SubscriptionUsageSnapshot } from "./subscriptionUsageSnapshot"; -export function publishSubscriptionUsage(snapshot: SubscriptionUsageSnapshot) { - requireOptionalNativeModule<{ updateSnapshot: (snapshot: string) => void }>( - "T3SubscriptionWidget", - )?.updateSnapshot(JSON.stringify(snapshot)); +let tapUrl: string | undefined; +let listening = false; + +export async function publishSubscriptionUsage(snapshot: SubscriptionUsageSnapshot) { + if (!requireOptionalNativeModule("ExpoWidgets")) return; + const [{ default: widget }, { addUserInteractionListener }] = await Promise.all([ + import("./SubscriptionUsage"), + import("expo-widgets"), + ]); + tapUrl = snapshot.url; + if (!listening) { + // expo-widgets has no Android counterpart to widgetURL: the card is a + // button whose tap is delivered to this process, so opening the app needs + // a live JS runtime. + listening = true; + addUserInteractionListener((event) => { + if (event.source === "SubscriptionUsage" && tapUrl) void Linking.openURL(tapUrl); + }); + } + widget.updateSnapshot(snapshot); + // Android has no timeline; an alarm re-renders the stored snapshot at each + // deadline so stale readings flip to "Open T3 to refresh" unattended. + requireOptionalNativeModule<{ schedule: (name: string, deadlines: number[]) => void }>( + "T3WidgetExpiry", + )?.schedule( + "SubscriptionUsage", + snapshot.providers.map((provider) => provider.expiresAt).filter((at) => at > 0), + ); } diff --git a/docs/user/usage.md b/docs/user/usage.md index 64f392d6e941..5c52122bf8a2 100644 --- a/docs/user/usage.md +++ b/docs/user/usage.md @@ -120,9 +120,9 @@ settings section when you no longer need it. ## Subscription usage widget Add **Subscription usage** from your iOS or Android widget gallery to see remaining Codex and -Claude quotas. Tap it to open **Usage → Limits**. On iOS, use **Edit Widget** to choose Session, -Weekly, or both for each provider. Reopen T3 to refresh expired readings. The Android widget -requires Android 12L or later. +Claude quotas. Tap it to open **Usage → Limits**; on Android this works while T3 is running in +the background, otherwise open the app from the launcher. On iOS, use **Edit Widget** to choose +Session, Weekly, or both for each provider. Reopen T3 to refresh expired readings. ## Keyboard shortcuts From 09388bf2da51b958fe5c11fb5bade155fe575e58 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:23 -0700 Subject: [PATCH 04/32] feat(mobile): degrade the agent Live Activity once its content goes stale (#12047) Co-authored-by: Claude Fable 5 --- .../agent-awareness/agentLiveActivity.ios.ts | 4 +- .../agent-awareness/agentLiveActivity.ts | 1 + .../agent-awareness/remoteRegistration.ts | 63 +++++++++++-------- apps/mobile/src/widgets/AgentActivity.test.ts | 20 ++++++ apps/mobile/src/widgets/AgentActivity.tsx | 32 +++++++--- 5 files changed, 85 insertions(+), 35 deletions(-) diff --git a/apps/mobile/src/features/agent-awareness/agentLiveActivity.ios.ts b/apps/mobile/src/features/agent-awareness/agentLiveActivity.ios.ts index ab078b29a665..1cb7369af559 100644 --- a/apps/mobile/src/features/agent-awareness/agentLiveActivity.ios.ts +++ b/apps/mobile/src/features/agent-awareness/agentLiveActivity.ios.ts @@ -4,6 +4,6 @@ export function getAgentLiveActivities() { return AgentActivity.getInstances(); } -export function startAgentLiveActivity(props: AgentActivityProps) { - return AgentActivity.start(props); +export function startAgentLiveActivity(props: AgentActivityProps, staleDate?: Date) { + return AgentActivity.start(props, undefined, staleDate); } diff --git a/apps/mobile/src/features/agent-awareness/agentLiveActivity.ts b/apps/mobile/src/features/agent-awareness/agentLiveActivity.ts index 44ac017984d9..18c3ffcf519b 100644 --- a/apps/mobile/src/features/agent-awareness/agentLiveActivity.ts +++ b/apps/mobile/src/features/agent-awareness/agentLiveActivity.ts @@ -7,6 +7,7 @@ export function getAgentLiveActivities(): Array export function startAgentLiveActivity( _props: AgentActivityProps, + _staleDate?: Date, ): LiveActivity | null { return null; } diff --git a/apps/mobile/src/features/agent-awareness/remoteRegistration.ts b/apps/mobile/src/features/agent-awareness/remoteRegistration.ts index a6c31594327a..7ed7ddc8bae1 100644 --- a/apps/mobile/src/features/agent-awareness/remoteRegistration.ts +++ b/apps/mobile/src/features/agent-awareness/remoteRegistration.ts @@ -83,6 +83,11 @@ const activityPushTokenListeners = new WeakSet> // foreground after real time away still triggers a replay. Cleared on // sign-out/identity change alongside the device registration state. const ACTIVITY_TOKEN_REREGISTER_INTERVAL_MS = 60_000; +// Locally started activities carry the same stale window the relay puts on +// every push (STALE_AFTER_SECONDS in ApnsClient.ts), so a card whose relay +// registration never lands still degrades instead of looking alive forever. +const LIVE_ACTIVITY_STALE_AFTER_MS = 10 * 60_000; +const liveActivityStaleDate = () => new Date(Date.now() + LIVE_ACTIVITY_STALE_AFTER_MS); const registeredActivityPushTokens = new Map(); let androidDeviceReplayedAt: number | null = null; let pushTokenSubscription: { remove: () => void } | null = null; @@ -527,25 +532,28 @@ function armAgentAwarenessLiveActivityForLocalWorkNow(input: { return; } const nowIso = new Date(Date.now()).toISOString(); - const activity = startAgentLiveActivity({ - title: "T3 Code", - subtitle: "Agent work in progress", - activeCount: 1, - updatedAt: nowIso, - activities: [ - { - environmentId: "", - threadId: "", - projectTitle: input.projectTitle, - threadTitle: input.threadTitle, - modelTitle: "", - phase: "starting", - status: "Connecting", - updatedAt: nowIso, - deepLink: "/", - }, - ], - }); + const activity = startAgentLiveActivity( + { + title: "T3 Code", + subtitle: "Agent work in progress", + activeCount: 1, + updatedAt: nowIso, + activities: [ + { + environmentId: "", + threadId: "", + projectTitle: input.projectTitle, + threadTitle: input.threadTitle, + modelTitle: "", + phase: "starting", + status: "Connecting", + updatedAt: nowIso, + deepLink: "/", + }, + ], + }, + liveActivityStaleDate(), + ); if (!activity) { return; } @@ -1131,13 +1139,16 @@ export function refreshActiveLiveActivityRemoteRegistration(): Effect.Effect< const aggregate = snapshot.aggregate; const primed = yield* Effect.try({ try: () => - startAgentLiveActivity({ - title: aggregate.title, - subtitle: aggregate.subtitle, - activeCount: aggregate.activeCount, - updatedAt: aggregate.updatedAt, - activities: aggregate.activities, - }), + startAgentLiveActivity( + { + title: aggregate.title, + subtitle: aggregate.subtitle, + activeCount: aggregate.activeCount, + updatedAt: aggregate.updatedAt, + activities: aggregate.activities, + }, + liveActivityStaleDate(), + ), catch: (cause) => new AgentAwarenessOperationError({ operation: "prime-live-activity", diff --git a/apps/mobile/src/widgets/AgentActivity.test.ts b/apps/mobile/src/widgets/AgentActivity.test.ts index 467f290a1575..bf02bb138c2f 100644 --- a/apps/mobile/src/widgets/AgentActivity.test.ts +++ b/apps/mobile/src/widgets/AgentActivity.test.ts @@ -82,6 +82,26 @@ describe("AgentActivity widget layout", () => { expect(banner).toContain("#fcd34d"); // amber-300: waiting_for_approval }); + it("degrades in-flight rows once the system marks the activity stale", () => { + const layout = AgentActivity( + { + ...props, + activeCount: 2, + activities: [ + makeRow({}), + makeRow({ threadId: "thread-2", phase: "completed", status: "Done" }), + ], + }, + { ...environment, isStale: true } as never, + ); + const banner = JSON.stringify(layout.banner); + expect(banner).toContain("Agent status out of date"); + expect(banner).toContain("Out of date"); + expect(banner).not.toContain("#7dd3fc"); // sky-300: running + expect(banner).toContain("Done"); + expect(JSON.stringify(layout.minimal)).not.toContain("2"); + }); + it("switches to the web sidebar's light palette when the scheme is light", () => { // macOS (iPhone Mirroring / Mac notification center) renders the activity // on a light background; the dark-material palette is illegible there. diff --git a/apps/mobile/src/widgets/AgentActivity.tsx b/apps/mobile/src/widgets/AgentActivity.tsx index 3e9b417c5aae..bc27e8b88113 100644 --- a/apps/mobile/src/widgets/AgentActivity.tsx +++ b/apps/mobile/src/widgets/AgentActivity.tsx @@ -88,6 +88,8 @@ export function AgentActivity( return isLightScheme ? "#dc2626" : "#fca5a5"; // red-600 / red-300 case "completed": return isLightScheme ? "#059669" : "#6ee7b7"; // emerald-600 / emerald-300 + case "stale": + return secondaryForeground; case "starting": case "running": default: @@ -103,20 +105,28 @@ export function AgentActivity( if (phase === "running" || phase === "starting") return 2; return 3; }; - const ordered = [...props.activities].sort( - (a, b) => phasePriority(a.phase) - phasePriority(b.phase), - ); + // Past the stale date the system stops vouching for the content, so every + // in-flight row degrades to "stale" rather than claiming an agent is still + // working. Terminal phases keep their own state. + const activities: ReadonlyArray = environment.isStale + ? props.activities.map((row) => + row.phase === "completed" || row.phase === "failed" + ? row + : { ...row, phase: "stale", status: "Out of date" }, + ) + : props.activities; + const ordered = [...activities].sort((a, b) => phasePriority(a.phase) - phasePriority(b.phase)); const row0 = ordered[0]; const row1 = ordered[1]; const row2 = ordered[2]; const row3 = ordered[3]; const row4 = ordered[4]; - const attentionRows = props.activities.filter( + const attentionRows = activities.filter( (row) => row.phase === "waiting_for_approval" || row.phase === "waiting_for_input", ); const attentionRow = attentionRows[0]; - const failedRow = props.activities.find((row) => row.phase === "failed"); + const failedRow = activities.find((row) => row.phase === "failed"); const heroRow = attentionRow ?? failedRow ?? row0; const tint = phaseTint(heroRow?.phase); // Headline count leans on the accent when a human is actually blocked. @@ -141,12 +151,20 @@ export function AgentActivity( // the two parts in-line so the attention half can carry the accent color; // `summary` is the short form for tight spots (expanded center, watch card). const agentWord = props.activeCount === 1 ? "agent" : "agents"; - const agentsLabel = allDone ? outcomeLabel : `${props.activeCount} active ${agentWord}`; + const agentsLabel = allDone + ? outcomeLabel + : environment.isStale + ? "Agent status out of date" + : `${props.activeCount} active ${agentWord}`; const attentionSuffix = attentionRows.length > 0 ? `${attentionRows.length} need${attentionRows.length === 1 ? "s" : ""} attention` : ""; - const activeLabel = allDone ? doneLabel : `${props.activeCount} active`; + const activeLabel = allDone + ? doneLabel + : environment.isStale + ? "Out of date" + : `${props.activeCount} active`; const summary = attentionSuffix || activeLabel; // Any registered scheme variant routes back to this app; taps are delivered From 438af295fefdd04cc38629f902d7faa07cf39712 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:23 -0700 Subject: [PATCH 05/32] feat(notifications): stack agent alerts by thread on both platforms (#12048) Co-authored-by: Claude Fable 5 --- .../AgentNotifications.kt | 27 ++++++++++++++++- .../AgentNotificationsTest.kt | 30 +++++++++++++++++-- .../src/agentActivity/ApnsClient.test.ts | 1 + infra/relay/src/agentActivity/ApnsClient.ts | 9 ++++++ .../src/agentActivity/FcmDeliveries.test.ts | 25 ++++++++++++++++ .../relay/src/agentActivity/FcmDeliveries.ts | 6 ++-- 6 files changed, 92 insertions(+), 6 deletions(-) diff --git a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt index 00af98ac4b28..09f9e278f12f 100644 --- a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt +++ b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt @@ -84,7 +84,10 @@ object AgentNotifications { cancelActivity(context) context.getSharedPreferences(STORE, Context.MODE_PRIVATE).edit().clear().apply() val manager = manager(context) - manager.activeNotifications.filter { it.tag == ACTIVITY_TAG || it.tag == ALERT_TAG } + manager.activeNotifications.filter { + it.tag == ACTIVITY_TAG || it.tag == ALERT_TAG || + it.tag?.startsWith("$ALERT_TAG-summary:") == true + } .forEach { manager.cancel(it.tag, it.id) } } @@ -157,13 +160,35 @@ object AgentNotifications { // Grouped alerts list up to five 120-character thread titles. val body = data["alert_body"].orEmpty().take(608) val id = alertId.hashCode() + val group = data["alert_group"]?.takeIf { it.isNotBlank() } ?: ALERT_TAG val notification = base(context, ALERT_CHANNEL) .setContentTitle(title).setContentText(body) .setStyle(NotificationCompat.BigTextStyle().bigText(body)) .setAutoCancel(true) + .setGroup(group) .setContentIntent(contentIntent(context, scheme, data["alert_path"], id)) .build() manager(context).notify(ALERT_TAG, id, notification) + val children = manager(context).activeNotifications.filter { + it.tag == ALERT_TAG && it.notification.group == group + } + if (children.size > 1) { + val style = NotificationCompat.InboxStyle() + children.forEach { + style.addLine(it.notification.extras.getCharSequence(android.app.Notification.EXTRA_TEXT)) + } + val summary = base(context, ALERT_CHANNEL) + .setContentTitle(title) + .setContentText(body) + .setStyle(style) + .setGroup(group) + .setGroupSummary(true) + .setSilent(true) + .setAutoCancel(true) + .setContentIntent(contentIntent(context, scheme, data["alert_path"], 0)) + .build() + manager(context).notify("$ALERT_TAG-summary:$group", 0, summary) + } } /** diff --git a/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt b/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt index 3e9b3b24c193..3852e3e2a0b2 100644 --- a/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt +++ b/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt @@ -60,6 +60,7 @@ class AgentNotificationsTest { "activity_body" to "Test thread · Working", "activity_path" to "/threads/environment/thread", "alert_id" to alertId, + "alert_group" to "environment/thread", "alert_title" to "Test thread", "alert_body" to "Done: Test project", "alert_path" to "/threads/environment/thread", @@ -76,6 +77,12 @@ class AgentNotificationsTest { assertEquals("alert-0".hashCode(), manager.activeNotifications.single().id) } + @Test + fun alertsStackByThreadGroup() { + AgentNotifications.receive(context, update("grouped", false)) + assertEquals("environment/thread", manager.activeNotifications.single().notification.group) + } + @Test fun missingLauncherDoesNotDiscardTheAlert() { shadowOf(context.packageManager).removeActivity(ComponentName(context, Activity::class.java)) @@ -142,6 +149,22 @@ class AgentNotificationsTest { assertEquals("background-completion".hashCode(), manager.activeNotifications.single().id) } + @Test + fun repeatedThreadAlertsHaveOneSilentSummaryAndClearTogether() { + AgentNotifications.receive(context, update("first", false) + ("alert_group" to "thread-group")) + AgentNotifications.receive(context, update("second", false) + ("alert_group" to "thread-group")) + + val summary = manager.activeNotifications.single { + it.notification.flags and Notification.FLAG_GROUP_SUMMARY != 0 + } + assertEquals("thread-group", summary.notification.group) + assertEquals(3, manager.activeNotifications.size) + assertEquals(null, summary.notification.sound) + + AgentNotifications.clear(context) + assertTrue(manager.activeNotifications.isEmpty()) + } + @Test fun groupedAlertDisplaysEveryThreadAndRetriesStaySilent() { val titles = (1..5).map { "Thread $it " + "x".repeat(111) }.joinToString(", ") @@ -286,11 +309,11 @@ class AgentNotificationsTest { context, update("older-alert", false) + ("updated_at" to (now - 1000).toString()) ) - assertEquals(3, manager.activeNotifications.size) + assertEquals(4, manager.activeNotifications.size) assertEquals(1, manager.activeNotifications.count { it.tag == "t3-agent-activity" }) shadowOf(manager).setNotificationsEnabled(false) AgentNotifications.receive(context, update("revoked-permission", true)) - assertEquals(3, manager.activeNotifications.size) + assertEquals(4, manager.activeNotifications.size) } @Test @@ -503,7 +526,8 @@ class AgentNotificationsTest { AgentNotifications.expire(context, expiresAt + 60_000) assertEquals(1, manager.activeNotifications.count { it.tag == "t3-agent-activity" }) AgentNotifications.expire(context, expiresAt + 2 * 60 * 60 * 1000L) - assertTrue(manager.activeNotifications.all { it.tag == "t3-agent-alert" }) + assertEquals(2, manager.activeNotifications.count { it.tag == "t3-agent-alert" }) + assertTrue(manager.activeNotifications.none { it.tag == "t3-agent-activity" }) assertTrue(alarms.scheduledAlarms.isEmpty()) } diff --git a/infra/relay/src/agentActivity/ApnsClient.test.ts b/infra/relay/src/agentActivity/ApnsClient.test.ts index 03010ce48ce5..6c54600e0543 100644 --- a/infra/relay/src/agentActivity/ApnsClient.test.ts +++ b/infra/relay/src/agentActivity/ApnsClient.test.ts @@ -187,6 +187,7 @@ describe("ApnsClient", () => { body: "Input: Project", }, sound: "default", + "thread-id": "env/thread", }, environmentId: "env", threadId: "thread", diff --git a/infra/relay/src/agentActivity/ApnsClient.ts b/infra/relay/src/agentActivity/ApnsClient.ts index 93c47af02e36..ec841be29b42 100644 --- a/infra/relay/src/agentActivity/ApnsClient.ts +++ b/infra/relay/src/agentActivity/ApnsClient.ts @@ -168,6 +168,12 @@ function makeLiveActivityRequest(input: MakeLiveActivityRequestInput): ApnsLiveA }; } +function notificationThreadId(notification: ApnsNotificationPayload): string { + return notification.threadId.length > 0 + ? `${notification.environmentId}/${notification.threadId}` + : "t3-agent-alerts"; +} + function makePushNotificationRequest(input: { readonly token: string; readonly notification: ApnsNotificationPayload; @@ -182,6 +188,9 @@ function makePushNotificationRequest(input: { body: input.notification.body, }, sound: "default", + // Notification Center stacks alerts by thread so a chatty thread does + // not bury the others; a grouped alert for several threads stays alone. + "thread-id": notificationThreadId(input.notification), }, environmentId: input.notification.environmentId, threadId: input.notification.threadId, diff --git a/infra/relay/src/agentActivity/FcmDeliveries.test.ts b/infra/relay/src/agentActivity/FcmDeliveries.test.ts index 8f061fca16ff..91ad9ad301e3 100644 --- a/infra/relay/src/agentActivity/FcmDeliveries.test.ts +++ b/infra/relay/src/agentActivity/FcmDeliveries.test.ts @@ -454,9 +454,34 @@ describe("Android delivery routing", () => { ).toMatchObject({ alert_title: `${"T".repeat(117)}...`, alert_body: `Done: ${"P".repeat(111)}...`, + alert_group: JSON.stringify([state.environmentId, state.threadId]), }); }); + it("keeps notification groups distinct when identifiers contain slashes", () => { + const left = androidAlertForState( + { + ...state, + environmentId: EnvironmentId.make("a/b"), + threadId: ThreadId.make("c"), + phase: "completed", + }, + preferences, + 0, + ); + const right = androidAlertForState( + { + ...state, + environmentId: EnvironmentId.make("a"), + threadId: ThreadId.make("b/c"), + phase: "completed", + }, + preferences, + 0, + ); + expect(left?.alert_group).not.toBe(right?.alert_group); + }); + it.effect( "queues Android devices and sends the latest aggregate instead of a stale running state", () => { diff --git a/infra/relay/src/agentActivity/FcmDeliveries.ts b/infra/relay/src/agentActivity/FcmDeliveries.ts index 8f998d9d9574..3433055f5dca 100644 --- a/infra/relay/src/agentActivity/FcmDeliveries.ts +++ b/infra/relay/src/agentActivity/FcmDeliveries.ts @@ -67,6 +67,7 @@ export function androidAlertForState( const notification = notificationForActivity({ ...state, status: statusForPhase(state.phase) }); return { alert_id: JSON.stringify([state.environmentId, state.threadId, state.phase, state.updatedAt]), + alert_group: JSON.stringify([state.environmentId, state.threadId]), alert_title: notification.title, alert_body: notification.body, alert_path: notification.deepLink, @@ -92,6 +93,7 @@ export function androidAlertForAggregate(input: { const notification = notificationForActivity(first); return { alert_id: JSON.stringify([first.environmentId, first.threadId, first.phase, first.updatedAt]), + alert_group: JSON.stringify([first.environmentId, first.threadId]), alert_title: notification.title, alert_body: notification.body, alert_path: notification.deepLink, @@ -210,7 +212,7 @@ export const make = Effect.gen(function* () { const previousAggregate = target.last_aggregate_json ? Option.getOrNull(decodePreviousActivity(target.last_aggregate_json)) : null; - let alert: ReturnType = null; + let alert: ReturnType = null; // Deletion jobs can observe another thread's newly completed state. They // update the card, but must leave that transition for its own alert job. // Registration replay deliberately establishes a silent baseline. @@ -291,7 +293,7 @@ export const make = Effect.gen(function* () { // A registration replay must clear an orphan even when the relay has // already forgotten its baseline. Finished cards are visible, but idle. if (!displayedAggregate && !alert && !previousAggregate && job.state !== null) return; - const data = { + const data: Record = { t3_kind: "agent_activity", device_id: job.deviceId, user_id: job.userId, From ce920f2ac893051bff2108c03346bd35340fd988 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:24 -0700 Subject: [PATCH 06/32] chore(mobile): drive dev-menu suppression from the dev-client launch URL (#12049) Co-authored-by: Claude Fable 5 --- .agents/skills/test-t3-mobile/SKILL.md | 3 +++ scripts/mobile-showcase.ts | 33 ++++++++------------------ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/.agents/skills/test-t3-mobile/SKILL.md b/.agents/skills/test-t3-mobile/SKILL.md index 1222449cd8a6..b2f5443e431a 100644 --- a/.agents/skills/test-t3-mobile/SKILL.md +++ b/.agents/skills/test-t3-mobile/SKILL.md @@ -41,6 +41,9 @@ Start `vp run dev:client` from `apps/mobile`, or reuse a healthy Metro belonging to this checkout. Open its printed development-client URL with AgentDevice `open com.t3tools.t3code.dev ` and all returned target arguments. The device must be able to reach both Metro and the isolated backend. +Append `&disableAutoLaunch=1&disableFab=1` to the development-client URL query +when developer chrome would obscure screenshots or taps; the SDK 58 dev client +applies these preferences before the app loads. ## Pair and verify diff --git a/scripts/mobile-showcase.ts b/scripts/mobile-showcase.ts index 2b141e12164f..772ab3896350 100644 --- a/scripts/mobile-showcase.ts +++ b/scripts/mobile-showcase.ts @@ -34,6 +34,9 @@ const REPO_ROOT = NodePath.resolve(NodePath.dirname(NodeURL.fileURLToPath(import const MOBILE_ROOT = NodePath.join(REPO_ROOT, "apps/mobile"); const ANDROID_PACKAGE = "com.t3tools.t3code"; const APP_SCHEME = "t3code"; +// expo-dev-launcher reads these off the manifest URL and updates the dev menu +// preferences before the app loads, keeping captures free of dev chrome. +const DEV_CLIENT_LAUNCH_FLAGS = "disableOnboarding=1&disableFab=1&disableAutoLaunch=1"; const IOS_READY_FILENAME = "T3ShowcaseReadyScene"; const SERVER_HOST = "0.0.0.0"; const IOS_SIMULATOR_ARCH = NodeProcess.arch === "arm64" ? "arm64" : "x86_64"; @@ -1107,25 +1110,9 @@ async function captureIos( await runCommand("xcrun", ["simctl", "install", simulator.udid, appPath]); } - for (const [key, value] of [ - ["EXDevMenuIsOnboardingFinished", "true"], - ["EXDevMenuShowFloatingActionButton", "false"], - ["EXDevMenuShowsAtLaunch", "false"], - ] as const) { - await runCommand("xcrun", [ - "simctl", - "spawn", - simulator.udid, - "defaults", - "write", - ANDROID_PACKAGE, - key, - "-bool", - value, - ]); - } - - const metroUrl = `http://${metroHost}:${config.metroPort}?disableOnboarding=1`; + // The dev-client launch URL carries the dev menu preferences (SDK 58), so + // nothing is written into the app container ahead of launch. + const metroUrl = `http://${metroHost}:${config.metroPort}?${DEV_CLIENT_LAUNCH_FLAGS}`; const scenePath = NodePath.join( await iosAppContainer(simulator.udid), "Library/Caches/T3ShowcaseScene", @@ -1357,12 +1344,12 @@ async function writeAndroidShowcaseScene(serial: string, scene: ShowcaseScene): ]); } +// Gesture and key-command toggles have no launch-URL flag, so they still go +// through the preferences file; onboarding, auto-launch and the floating button +// come from DEV_CLIENT_LAUNCH_FLAGS on the launch URL. async function prepareAndroidShowcaseApp(serial: string): Promise { const preferences = ` - - - @@ -1435,7 +1422,7 @@ async function captureAndroid( "-a", "android.intent.action.VIEW", "-d", - `${APP_SCHEME}://expo-development-client/?url=${metroUrl}`, + `'${APP_SCHEME}://expo-development-client/?url=${metroUrl}&${DEV_CLIENT_LAUNCH_FLAGS}'`, "--es", "showcasePairingUrl", encodeAndroidPairingUrls(pairingUrls), From 9962e6986db68cd5537d23153e7898d6b3696b85 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:24 -0700 Subject: [PATCH 07/32] fix(mobile): read display scale and width from the view's scene, not UIScreen.main (#12050) Co-authored-by: Claude Fable 5 --- .../t3-composer-editor/ios/T3ComposerEditorView.swift | 10 +++++++++- .../modules/t3-review-diff/ios/T3ReviewDiffView.swift | 4 ++-- .../modules/t3-terminal/ios/T3TerminalView.swift | 7 +++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift b/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift index 50ac2afbcb46..bff803f69c00 100644 --- a/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift +++ b/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorView.swift @@ -436,6 +436,7 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate, UITextDro private var iconImages: [String: UIImage] = [:] private var pendingIconUris = Set() private var tokensNeedRebuild = false + private var chipsNeedMeasuredWidth = false let onComposerChange = EventDispatcher() let onComposerSelectionChange = EventDispatcher() @@ -571,6 +572,10 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate, UITextDro public override func layoutSubviews() { super.layoutSubviews() textView.frame = bounds + if chipsNeedMeasuredWidth, bounds.width > 0 { + chipsNeedMeasuredWidth = false + applyControlledDocument(force: true) + } let placeholderX = textView.textContainerInset.left + textView.textContainer.lineFragmentPadding let placeholderY = textView.textContainerInset.top let placeholderWidth = max( @@ -970,7 +975,10 @@ public final class T3ComposerEditorView: ExpoView, UITextViewDelegate, UITextDro // `maximumWidth` does, so the chip always fits the line it sits on. let availableWidth = textView.textContainer.size.width > 0 ? textView.textContainer.size.width - textView.textContainer.lineFragmentPadding * 2 - : UIScreen.main.bounds.width + : (textView.window?.bounds.width ?? bounds.width) + if availableWidth <= 0 { + chipsNeedMeasuredWidth = true + } let maximumLabelWidth = max(chipFontSize * 3, availableWidth - padding * 2 - iconWidth - iconGap) paragraph.lineBreakMode = .byTruncatingMiddle attributedLabel.addAttribute( diff --git a/apps/mobile/modules/t3-review-diff/ios/T3ReviewDiffView.swift b/apps/mobile/modules/t3-review-diff/ios/T3ReviewDiffView.swift index e2400e0a9393..928e3b5669d1 100644 --- a/apps/mobile/modules/t3-review-diff/ios/T3ReviewDiffView.swift +++ b/apps/mobile/modules/t3-review-diff/ios/T3ReviewDiffView.swift @@ -1923,7 +1923,7 @@ private final class ReviewDiffContentView: UIView, UIGestureRecognizerDelegate { theme.headerBackground.setFill() context.fill(cardRect) - let hairline = 1 / UIScreen.main.scale + let hairline = 1 / traitCollection.displayScale theme.border.setFill() context.fill(CGRect(x: cardRect.minX, y: cardRect.maxY - hairline, width: cardRect.width, height: hairline)) @@ -1982,7 +1982,7 @@ private final class ReviewDiffContentView: UIView, UIGestureRecognizerDelegate { theme.background.setFill() context.fill(rect) - let hairline = 1 / UIScreen.main.scale + let hairline = 1 / traitCollection.displayScale theme.border.withAlphaComponent(0.65).setFill() context.fill(CGRect(x: 0, y: rect.maxY - hairline, width: rect.width, height: hairline)) diff --git a/apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift b/apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift index 69f8a6d4af16..9e382bfcd7ed 100644 --- a/apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift +++ b/apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift @@ -315,7 +315,8 @@ public final class T3TerminalView: ExpoView, UITextFieldDelegate { applyTheme() clipsToBounds = true - contentScaleFactor = UIScreen.main.scale + // The real scale arrives with the window; layoutSubviews corrects it. + contentScaleFactor = traitCollection.displayScale terminalViewport.clipsToBounds = true terminalViewport.contentScaleFactor = contentScaleFactor @@ -677,7 +678,9 @@ public final class T3TerminalView: ExpoView, UITextFieldDelegate { } private func updateContentScale() { - let scale = window?.screen.scale ?? UIScreen.main.scale + // The trait collection follows the scene the view is in, which matters once + // iPhone apps run resizable and on external displays; UIScreen.main does not. + let scale = traitCollection.displayScale if contentScaleFactor != scale { contentScaleFactor = scale } From 1e9c36023c898bfcab6dce862e105441b85ec22e Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:25 -0700 Subject: [PATCH 08/32] refactor(mobile): adopt Expo Modules 2.0 for function-only native members (#12051) Co-authored-by: Claude Fable 5 --- .../ios/T3ComposerEditorModule.swift | 16 +- .../ios/T3NativeControlsModule.swift | 185 +++++++++--------- 2 files changed, 102 insertions(+), 99 deletions(-) diff --git a/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorModule.swift b/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorModule.swift index 6f2428a6a7de..94eb06671558 100644 --- a/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorModule.swift +++ b/apps/mobile/modules/t3-composer-editor/ios/T3ComposerEditorModule.swift @@ -36,14 +36,18 @@ enum T3ComposerClipboard { } } +// Expo Modules 2.0: the clipboard function is a @JS member; the view stays in +// definition() until the 2.0 view API lands. +@ExpoModule("T3ComposerEditor") public class T3ComposerEditorModule: Module { - public func definition() -> ModuleDefinition { - Name("T3ComposerEditor") - - AsyncFunction("writeContextClipboard") { (text: String, fragment: String) in - T3ComposerClipboard.write(text: text, fragment: fragment) - }.runOnQueue(.main) + // UIPasteboard is main-thread only, so the member is main-actor isolated. + @JS + @MainActor + func writeContextClipboard(text: String, fragment: String) async { + T3ComposerClipboard.write(text: text, fragment: fragment) + } + public func definition() -> ModuleDefinition { View(T3ComposerEditorView.self) { Prop("controlledDocumentJson") { (view: T3ComposerEditorView, documentJson: String) in view.setControlledDocumentJson(documentJson) diff --git a/apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift b/apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift index a7bf5337e8f1..a5813c8a0e8b 100644 --- a/apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift +++ b/apps/mobile/modules/t3-native-controls/ios/T3NativeControlsModule.swift @@ -2,14 +2,15 @@ import ExpoModulesCore import Security import UIKit +// Expo Modules 2.0: plain members marked @JS are bound by the macro, while the +// views and main-queue presenters stay in definition(). Both are merged. +@ExpoModule("T3NativeControls") public final class T3NativeControlsModule: Module { private let presentationSources = T3PresentationSources() private var videoPresentation: T3NativeVideoPresentation? private var filePresentation: T3NativeFilePresentation? public func definition() -> ModuleDefinition { - Name("T3NativeControls") - AsyncFunction("presentVideo") { (url: URL, title: String, sourceIdentifier: String, identifier: String, promise: Promise) in try self.presentVideo( url: url, @@ -20,19 +21,11 @@ public final class T3NativeControlsModule: Module { ) }.runOnQueue(.main) - AsyncFunction("dismissVideo") { (identifier: String) in - self.dismissVideo(identifier: identifier) - }.runOnQueue(.main) - AsyncFunction("presentFile") { (url: URL, title: String, sourceIdentifier: String, identifier: String, promise: Promise) in try self.presentFile(url: url, title: title, sourceIdentifier: sourceIdentifier, identifier: identifier, promise: promise) }.runOnQueue(.main) - AsyncFunction("dismissFile") { (identifier: String) in - self.dismissFile(identifier: identifier) - }.runOnQueue(.main) - OnDestroy { let presentation = self.videoPresentation let file = self.filePresentation @@ -60,103 +53,109 @@ public final class T3NativeControlsModule: Module { AsyncFunction("shareFileFromSource") { (url: URL, title: String, identifier: String, promise: Promise) in try self.shareFile(url: url, title: title, sourceIdentifier: identifier, promise: promise) }.runOnQueue(.main) + } - Function("getShowcasePairingUrl") { - let arguments = ProcessInfo.processInfo.arguments - guard - let flagIndex = arguments.firstIndex(of: "--showcasePairingUrl"), - arguments.indices.contains(flagIndex + 1) - else { - return nil as String? - } - return arguments[flagIndex + 1] - } + // UIKit presenters are main-actor isolated rather than run on the JS thread + // the macro would otherwise pick. + @JS + @MainActor + func dismissVideo(identifier: String) async { + dismissVideoPresentation(identifier: identifier) + } + + @JS + @MainActor + func dismissFile(identifier: String) async { + dismissFilePresentation(identifier: identifier) + } - Function("getShowcaseScene") { () -> String? in - let scenePath = NSHomeDirectory() + "/Library/Caches/T3ShowcaseScene" - if let storedScene = try? String(contentsOfFile: scenePath, encoding: .utf8) - .trimmingCharacters(in: .whitespacesAndNewlines), !storedScene.isEmpty { - return storedScene + // Rotates the interface without Simulator menu UI scripting, which CI + // runners cannot perform (osascript is denied Accessibility access there). + @JS + @MainActor + func applyShowcaseOrientation(orientation: String) async { + let mask: UIInterfaceOrientationMask = orientation == "landscape" ? .landscapeRight : .portrait + for case let windowScene as UIWindowScene in UIApplication.shared.connectedScenes { + windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: mask)) { error in + NSLog("T3NativeControls applyShowcaseOrientation(\(orientation)) failed: \(error)") } - let arguments = ProcessInfo.processInfo.arguments - guard - let flagIndex = arguments.firstIndex(of: "--showcaseScene"), - arguments.indices.contains(flagIndex + 1) - else { - return nil as String? + for window in windowScene.windows { + window.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations() } - return arguments[flagIndex + 1] } + } - // The palette is fixed for the whole capture, so it only ever arrives as a - // launch argument — unlike the scene, which the runner rewrites in place. - Function("getShowcaseTheme") { () -> String? in - let arguments = ProcessInfo.processInfo.arguments - guard - let flagIndex = arguments.firstIndex(of: "--showcaseTheme"), - arguments.indices.contains(flagIndex + 1) - else { - return nil as String? - } - return arguments[flagIndex + 1] + // The geometry request above can fail transiently (for example before the + // scene is foreground-active), so callers poll this until it settles. + // Screen bounds — not the scene's interface orientation — decide the + // answer because they match the captured framebuffer: with iPadOS + // windowing active, a floating landscape window still reports a portrait + // screen, and screenshots would come out portrait. + @JS + @MainActor + func getInterfaceOrientation() async -> String { + guard + let windowScene = UIApplication.shared.connectedScenes + .compactMap({ $0 as? UIWindowScene }) + .first + else { + return "unknown" } + let bounds = windowScene.screen.coordinateSpace.bounds + return bounds.width > bounds.height ? "landscape" : "portrait" + } - Function("getShowcaseOrientation") { () -> String? in - let arguments = ProcessInfo.processInfo.arguments - guard - let flagIndex = arguments.firstIndex(of: "--showcaseOrientation"), - arguments.indices.contains(flagIndex + 1) - else { - return nil as String? - } - return arguments[flagIndex + 1] + private func launchArgument(_ flag: String) -> String? { + let arguments = ProcessInfo.processInfo.arguments + guard + let flagIndex = arguments.firstIndex(of: flag), + arguments.indices.contains(flagIndex + 1) + else { + return nil } + return arguments[flagIndex + 1] + } - // Rotates the interface without Simulator menu UI scripting, which CI - // runners cannot perform (osascript is denied Accessibility access there). - AsyncFunction("applyShowcaseOrientation") { (orientation: String) in - guard #available(iOS 16.0, *) else { return } - let mask: UIInterfaceOrientationMask = orientation == "landscape" ? .landscapeRight : .portrait - for case let windowScene as UIWindowScene in UIApplication.shared.connectedScenes { - windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: mask)) { error in - NSLog("T3NativeControls applyShowcaseOrientation(\(orientation)) failed: \(error)") - } - for window in windowScene.windows { - window.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations() - } - } - }.runOnQueue(.main) - - // The geometry request above can fail transiently (for example before the - // scene is foreground-active), so callers poll this until it settles. - // Screen bounds — not the scene's interface orientation — decide the - // answer because they match the captured framebuffer: with iPadOS - // windowing active, a floating landscape window still reports a portrait - // screen, and screenshots would come out portrait. - AsyncFunction("getInterfaceOrientation") { () -> String in - guard - let windowScene = UIApplication.shared.connectedScenes - .compactMap({ $0 as? UIWindowScene }) - .first - else { - return "unknown" - } - let bounds = windowScene.screen.coordinateSpace.bounds - return bounds.width > bounds.height ? "landscape" : "portrait" - }.runOnQueue(.main) + @JS + func getShowcasePairingUrl() -> String? { + launchArgument("--showcasePairingUrl") + } - Function("prepareShowcaseCapture") { - for itemClass in [kSecClassGenericPassword, kSecClassInternetPassword] { - SecItemDelete([kSecClass as String: itemClass] as CFDictionary) - } + @JS + func getShowcaseScene() -> String? { + let scenePath = NSHomeDirectory() + "/Library/Caches/T3ShowcaseScene" + if let storedScene = try? String(contentsOfFile: scenePath, encoding: .utf8) + .trimmingCharacters(in: .whitespacesAndNewlines), !storedScene.isEmpty { + return storedScene } + return launchArgument("--showcaseScene") + } + + // The palette is fixed for the whole capture, so it only ever arrives as a + // launch argument — unlike the scene, which the runner rewrites in place. + @JS + func getShowcaseTheme() -> String? { + launchArgument("--showcaseTheme") + } - Function("markShowcaseReady") { (scene: String) in - let readyPath = NSHomeDirectory() + "/Library/Caches/T3ShowcaseReadyScene" - try? scene.write(toFile: readyPath, atomically: true, encoding: .utf8) + @JS + func getShowcaseOrientation() -> String? { + launchArgument("--showcaseOrientation") + } + + @JS + func prepareShowcaseCapture() { + for itemClass in [kSecClassGenericPassword, kSecClassInternetPassword] { + SecItemDelete([kSecClass as String: itemClass] as CFDictionary) } } + @JS(.concurrent) + func markShowcaseReady(scene: String) async { + let readyPath = NSHomeDirectory() + "/Library/Caches/T3ShowcaseReadyScene" + try? scene.write(toFile: readyPath, atomically: true, encoding: .utf8) + } + private func presentVideo(url: URL, title: String, sourceIdentifier: String, identifier: String, promise: Promise) throws { let isPlayableURL = url.isFileURL ? FileManager.default.isReadableFile(atPath: url.path) @@ -179,7 +178,7 @@ public final class T3NativeControlsModule: Module { presentation.present(from: presenter, sources: presentationSources, sourceIdentifier: sourceIdentifier) } - private func dismissVideo(identifier: String) { + private func dismissVideoPresentation(identifier: String) { if videoPresentation?.identifier == identifier { videoPresentation?.dismiss() } } @@ -197,7 +196,7 @@ public final class T3NativeControlsModule: Module { file.present(url: url, title: title, from: presenter) } - private func dismissFile(identifier: String) { + private func dismissFilePresentation(identifier: String) { if filePresentation?.identifier == identifier { filePresentation?.dismiss() } } From bed69f6ea41dab13ec37afbaaa2c911a19865f7a Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 10:51:25 -0700 Subject: [PATCH 09/32] feat(mobile): suppress only the on-screen thread's alert on Android (#12052) Co-authored-by: Claude Fable 5 --- .../AgentNotifications.kt | 17 +++++-- .../T3AgentNotificationsModule.kt | 4 ++ .../AgentNotificationsTest.kt | 17 ++++++- .../agent-awareness/androidNotifications.ts | 6 +++ .../agent-awareness/notificationNavigation.ts | 11 ++++- docs/operations/android-notifications.md | 2 +- .../src/agentActivity/FcmDeliveries.test.ts | 47 ++++++++++--------- .../relay/src/agentActivity/FcmDeliveries.ts | 6 ++- 8 files changed, 78 insertions(+), 32 deletions(-) diff --git a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt index 09f9e278f12f..5c7cd2e43560 100644 --- a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt +++ b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/AgentNotifications.kt @@ -91,6 +91,13 @@ object AgentNotifications { .forEach { manager.cancel(it.tag, it.id) } } + /** Records the thread route the app is showing, or null when none is open. */ + @Volatile private var threadOnScreen: String? = null + + fun setThreadOnScreen(path: String?) { + threadOnScreen = path + } + @Synchronized fun dismiss(context: Context) { context.getSharedPreferences( @@ -138,9 +145,13 @@ object AgentNotifications { val seen = prefs.getString("seenAlertsOrdered", null)?.split('\n') ?: prefs.getStringSet("seenAlerts", emptySet()).orEmpty().toList() if (alertId != null && alertId !in seen) { - // Match iOS foreground presentation. Consume suppressed alerts as well, - // so a delivery retry cannot surface them after the app backgrounds. - if (!ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) { + // Consume suppressed alerts so retries cannot resurface them later. + val resumed = ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast( + Lifecycle.State.RESUMED + ) + val visibleThread = threadOnScreen + val onScreen = resumed && visibleThread != null && data["alert_path"] == visibleThread + if (!onScreen) { postAlert(context, scheme, data, alertId) } prefs.edit().remove("seenAlerts").putString( diff --git a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/T3AgentNotificationsModule.kt b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/T3AgentNotificationsModule.kt index 0a2d2b30589f..cbef915cb7da 100644 --- a/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/T3AgentNotificationsModule.kt +++ b/apps/mobile/modules/t3-agent-notifications/android/src/main/java/expo/modules/t3agentnotifications/T3AgentNotificationsModule.kt @@ -30,6 +30,10 @@ class T3AgentNotificationsModule : Module() { appContext.reactContext?.let { AgentNotifications.showcase(it, scheme, data) } } + Function("setThreadOnScreen") { path: String? -> + AgentNotifications.setThreadOnScreen(path) + } + Function("openLiveUpdateSettings") { val context = appContext.reactContext if (context == null || Build.VERSION.SDK_INT < 36) { diff --git a/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt b/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt index 3852e3e2a0b2..7492bf743dcb 100644 --- a/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt +++ b/apps/mobile/modules/t3-agent-notifications/android/src/test/java/expo/modules/t3agentnotifications/AgentNotificationsTest.kt @@ -49,6 +49,8 @@ class AgentNotificationsTest { ) AgentNotifications.clear(context) AgentNotifications.configure(context, "device", "user", "t3code-dev", true) + // The fixtures alert for this thread; a resumed app is showing it. + AgentNotifications.setThreadOnScreen("/threads/environment/thread") } private fun update(alertId: String, active: Boolean) = mapOf( @@ -93,6 +95,14 @@ class AgentNotificationsTest { ) } + @Test + fun foregroundAlertsForThreadsThatAreNotOnScreen() { + lifecycle.currentState = Lifecycle.State.RESUMED + AgentNotifications.setThreadOnScreen("/threads/environment/other") + AgentNotifications.receive(context, update("elsewhere", false)) + assertEquals("t3-agent-alert", manager.activeNotifications.single().tag) + } + @Test fun foregroundSuppressesAlertsWhileOngoingActivityStillUpdatesAndClears() { lifecycle.currentState = Lifecycle.State.RESUMED @@ -187,7 +197,7 @@ class AgentNotificationsTest { } @Test - fun foregroundSuppressedGroupCannotAppearOnBackgroundRetry() { + fun foregroundGroupForOtherThreadsAlertsOnceAcrossBackgroundRetry() { val grouped = update("group-attention", true) + mapOf( "alert_title" to "2 agents need attention", "alert_body" to "First thread, Second thread", @@ -195,10 +205,13 @@ class AgentNotificationsTest { ) lifecycle.currentState = Lifecycle.State.RESUMED AgentNotifications.receive(context, grouped) + assertEquals(1, manager.activeNotifications.count { it.tag == "t3-agent-alert" }) lifecycle.currentState = Lifecycle.State.CREATED AgentNotifications.receive(context, grouped) - assertEquals("t3-agent-activity", manager.activeNotifications.single().tag) + assertEquals(2, manager.activeNotifications.size) + assertEquals(1, manager.activeNotifications.count { it.tag == "t3-agent-activity" }) + assertEquals(1, manager.activeNotifications.count { it.tag == "t3-agent-alert" }) } @Test diff --git a/apps/mobile/src/features/agent-awareness/androidNotifications.ts b/apps/mobile/src/features/agent-awareness/androidNotifications.ts index a2a0945faaf1..73f84434d89d 100644 --- a/apps/mobile/src/features/agent-awareness/androidNotifications.ts +++ b/apps/mobile/src/features/agent-awareness/androidNotifications.ts @@ -5,6 +5,7 @@ import { Linking, Platform } from "react-native"; interface AndroidAgentNotifications { configure(deviceId: string, userId: string, scheme: string, ongoingEnabled: boolean): void; clear(): void; + setThreadOnScreen?(path: string | null): void; openLiveUpdateSettings?(): boolean; showShowcaseActivity?(scheme: string, data: Record): void; } @@ -42,6 +43,11 @@ export function clearAndroidAgentNotifications(): void { native?.clear?.(); } +/** Tells the FCM handler which thread route is on screen so its alerts stay quiet. */ +export function setAndroidThreadOnScreen(path: string | null): void { + native?.setThreadOnScreen?.(path); +} + export function supportsAndroidLiveUpdateSettings(): boolean { return Platform.OS === "android" && Number(Platform.Version) >= 36; } diff --git a/apps/mobile/src/features/agent-awareness/notificationNavigation.ts b/apps/mobile/src/features/agent-awareness/notificationNavigation.ts index ff65371ba3b6..099fb5055990 100644 --- a/apps/mobile/src/features/agent-awareness/notificationNavigation.ts +++ b/apps/mobile/src/features/agent-awareness/notificationNavigation.ts @@ -1,7 +1,8 @@ -import { useEffect, useRef } from "react"; +import { useEffect, useLayoutEffect, useRef } from "react"; import * as Notifications from "expo-notifications"; import { useLinkTo } from "@react-navigation/native"; +import { setAndroidThreadOnScreen } from "./androidNotifications"; import { foregroundNotificationBehavior } from "./foregroundNotificationBehavior"; import { routeAgentNotificationResponseOnce, threadDeepLinkOnScreen } from "./notificationPayload"; import { consumeLastAgentNotificationResponse } from "./notificationResponseConsumer"; @@ -12,7 +13,13 @@ export function useAgentNotificationNavigation(pathname: string): void { // Read through a ref so the native handler registered once below sees the // current route without re-registering on every navigation. const deepLinkOnScreen = useRef(null); - deepLinkOnScreen.current = threadDeepLinkOnScreen(pathname); + useLayoutEffect(() => { + const thread = threadDeepLinkOnScreen(pathname); + deepLinkOnScreen.current = thread; + // Android alerts are built natively from FCM data, so update the native + // route at commit time alongside the iOS handler's route reference. + setAndroidThreadOnScreen(thread); + }, [pathname]); useEffect(() => { Notifications.setNotificationHandler({ diff --git a/docs/operations/android-notifications.md b/docs/operations/android-notifications.md index 3ae100c39f5c..aa29ef3e1a7b 100644 --- a/docs/operations/android-notifications.md +++ b/docs/operations/android-notifications.md @@ -68,7 +68,7 @@ vp run push:android:smoke /path/service-account.json /path/device.json completed Supported states are `running`, `approval`, `input`, `completed`, `failed`, and `end`. Firebase acceptance is not proof that a device displayed the message. Check the actual notification, background the app, and test a notification tap. Also test dismissal, disabling ongoing activity, sign-out, token rotation, and delivery after the app process has exited. Android Settings **Force stop** intentionally prevents delivery until the app is opened again. -Android suppresses ordinary alerts while the app is foregrounded, matching iOS notification presentation. Activity cards still update in the foreground and retain finished results silently. Check that completion stays quiet with the app open, that a later completion alerts after backgrounding, and that retrying a foreground-suppressed alert does not show it later. This uses the app lifecycle on the receiving phone, not thread visibility on other clients. +With the app in the foreground, Android suppresses an alert only for the thread currently on screen, matching iOS notification presentation; alerts for other threads still show. Activity cards still update in the foreground and retain finished results silently. Check that completion stays quiet while its thread is open, alerts while another screen is open, alerts after backgrounding, and that retrying a suppressed alert does not show it later. This uses the app lifecycle and route on the receiving phone, not thread visibility on other clients. With ongoing activity enabled, verify two threads entering approval/input together produce one `2 agents need attention` alert, and two observed active threads completing/failing together produce one `2 agents finished` alert. The body lists their titles. The relay shares iOS transition selection and retains its delivered baseline when work finishes; publishing the same states again must not produce another alert. Grouped alerts open the aggregate’s priority thread; individual alerts retain their thread link. diff --git a/infra/relay/src/agentActivity/FcmDeliveries.test.ts b/infra/relay/src/agentActivity/FcmDeliveries.test.ts index 91ad9ad301e3..46254e1e8b43 100644 --- a/infra/relay/src/agentActivity/FcmDeliveries.test.ts +++ b/infra/relay/src/agentActivity/FcmDeliveries.test.ts @@ -225,28 +225,31 @@ describe("Android delivery routing", () => { ["waiting_for_approval", "waiting_for_input", "2 agents need attention", "true"], ["completed", "failed", "2 agents finished", "false"], ] as const) { - it.effect(`groups ${firstPhase} and ${secondPhase} once across their queued jobs`, () => { - const h = harness(); - h.current.otherStates = [secondState]; - return Effect.gen(function* () { - const delivery = yield* FcmDeliveries; - yield* delivery.process(h.job); - h.current.state = { ...state, phase: firstPhase }; - h.current.otherStates = [{ ...secondState, phase: secondPhase }]; - yield* delivery.process({ ...h.job, state: h.current.state }); - yield* delivery.process({ ...h.job, state: h.current.otherStates[0] }); - yield* delivery.process({ ...h.job, state: h.current.state }); - const alerts = h.sent.filter((message) => message.alert); - expect(alerts).toHaveLength(1); - expect(alerts[0]?.data).toMatchObject({ - alert_title: title, - alert_body: "Fix notifications, Second thread", - alert_path: firstPhase === "completed" ? secondState.deepLink : state.deepLink, - active, - }); - expect(h.marked.at(-1)?.aggregate?.activities).toHaveLength(2); - }).pipe(Effect.provide(h.layer)); - }); + it.effect( + `routes grouped ${firstPhase} and ${secondPhase} to the overview once across their queued jobs`, + () => { + const h = harness(); + h.current.otherStates = [secondState]; + return Effect.gen(function* () { + const delivery = yield* FcmDeliveries; + yield* delivery.process(h.job); + h.current.state = { ...state, phase: firstPhase }; + h.current.otherStates = [{ ...secondState, phase: secondPhase }]; + yield* delivery.process({ ...h.job, state: h.current.state }); + yield* delivery.process({ ...h.job, state: h.current.otherStates[0] }); + yield* delivery.process({ ...h.job, state: h.current.state }); + const alerts = h.sent.filter((message) => message.alert); + expect(alerts).toHaveLength(1); + expect(alerts[0]?.data).toMatchObject({ + alert_title: title, + alert_body: "Fix notifications, Second thread", + alert_path: "/", + active, + }); + expect(h.marked.at(-1)?.aggregate?.activities).toHaveLength(2); + }).pipe(Effect.provide(h.layer)); + }, + ); } it.effect("filters disabled event types before counting a group", () => { diff --git a/infra/relay/src/agentActivity/FcmDeliveries.ts b/infra/relay/src/agentActivity/FcmDeliveries.ts index 3433055f5dca..8f830a8af7b4 100644 --- a/infra/relay/src/agentActivity/FcmDeliveries.ts +++ b/infra/relay/src/agentActivity/FcmDeliveries.ts @@ -22,7 +22,7 @@ import * as AgentActivityRows from "./AgentActivityRows.ts"; import * as LiveActivities from "./LiveActivities.ts"; import * as FcmDeliveryQueueSender from "./FcmDeliveryQueueSender.ts"; import * as FcmClient from "./FcmClient.ts"; -import { androidActivityData, androidActivityHero, fitFcmData } from "./fcmPayloads.ts"; +import { androidActivityData, fitFcmData } from "./fcmPayloads.ts"; import { makeAggregateState, statusForPhase } from "./agentActivityAggregate.ts"; import { isExpiredAgentActivityState, notificationForActivity } from "./agentActivityPayloads.ts"; import { @@ -109,7 +109,9 @@ export function androidAlertForAggregate(input: { ), alert_title: alert.title, alert_body: alert.body, - alert_path: androidActivityHero(input.nextAggregate)?.deepLink ?? "/", + // A multi-thread alert targets the overview so one visible thread cannot + // suppress notifications for the other threads in the group. + alert_path: "/", }; } From b91e4668fa2b8e4ac0044e65a08dc6b5e51dfbcf Mon Sep 17 00:00:00 2001 From: oliver <97427849+flamboh@users.noreply.github.com> Date: Thu, 1 Oct 2026 11:55:51 -0700 Subject: [PATCH 10/32] feat(marketing): replace the screenshot crop with a designed social card (#13487) Co-authored-by: Claude Opus 5.5 --- apps/marketing/src/assets/social-card.webp | Bin 0 -> 181556 bytes apps/marketing/src/layouts/Layout.astro | 17 +++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 apps/marketing/src/assets/social-card.webp diff --git a/apps/marketing/src/assets/social-card.webp b/apps/marketing/src/assets/social-card.webp new file mode 100644 index 0000000000000000000000000000000000000000..cb4f9a0de722fb75f336e5d666812329a64b3778 GIT binary patch literal 181556 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 z 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 + ))} + + + ); +} diff --git a/apps/web/src/components/settings/ProviderSettingsPanel.tsx b/apps/web/src/components/settings/ProviderSettingsPanel.tsx index aa947d5d1de7..6b62b342c41b 100644 --- a/apps/web/src/components/settings/ProviderSettingsPanel.tsx +++ b/apps/web/src/components/settings/ProviderSettingsPanel.tsx @@ -59,6 +59,7 @@ import { isProviderUpdateActive, type ProviderSettingsUpdateCandidate, } from "../ProviderUpdateLaunchNotification.logic"; +import { ProviderUpdatesAction } from "../ProviderUpdatesAction"; import { Button } from "../ui/button"; import { Empty, @@ -1065,6 +1066,7 @@ export function EnvironmentProviderSettings({ variant="plain" headerAction={
+ {readOnly ? ( diff --git a/docs/user/updating.md b/docs/user/updating.md index 6909c7b6022d..79ceff4fdb50 100644 --- a/docs/user/updating.md +++ b/docs/user/updating.md @@ -56,6 +56,13 @@ update can roll back to the previous version. If the update still fails: 2. Check that you updated the server's machine, not only the device you are using. 3. For a command-line server, stop it and relaunch the exact version shown in the notice. +## Update providers + +**Settings → Providers** shows provider updates for the selected environment. +**Update all** updates every outdated provider on every connected environment +at once. Hover it to see which providers it will update. Providers that only +offer a manual update command are not included. + ## Mobile updates To update an environment from your phone, open **Settings → Environments** and From b33eda13998b5b0571daaf266c87f6f31af41f7d Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 1 Oct 2026 17:08:35 -0700 Subject: [PATCH 20/32] feat(web): beta Working section hides busy threads until they need you (#13926) Co-authored-by: Claude Opus 5.5 (1M context) --- .../settings/DesktopClientSettings.test.ts | 1 + apps/web/src/components/Sidebar.drag.test.ts | 22 ++ apps/web/src/components/Sidebar.drag.ts | 44 ++-- apps/web/src/components/Sidebar.logic.test.ts | 167 ++++++++++++++++ apps/web/src/components/Sidebar.logic.ts | 83 +++++++- apps/web/src/components/Sidebar.tsx | 188 ++++++++++++++++-- .../components/settings/SettingsPanels.tsx | 33 +++ .../src/components/settings/settingsSearch.ts | 6 + docs/user/thread-sidebar.md | 10 + packages/contracts/src/settings.ts | 7 + 10 files changed, 517 insertions(+), 44 deletions(-) diff --git a/apps/desktop/src/settings/DesktopClientSettings.test.ts b/apps/desktop/src/settings/DesktopClientSettings.test.ts index 53044dcf7e5d..235f3dd1d7d5 100644 --- a/apps/desktop/src/settings/DesktopClientSettings.test.ts +++ b/apps/desktop/src/settings/DesktopClientSettings.test.ts @@ -65,6 +65,7 @@ const clientSettings: ClientSettings = { sidebarThreadSortOrder: "created_at", sidebarThreadPreviewCount: 6, legacySidebarEnabled: false, + sidebarWorkingShelfEnabled: false, loadBalancingEnabled: false, loadBalancingWeights: { "environment-1": 75, "environment-2": 0 }, pullRequestMergeMethodOverrides: {}, diff --git a/apps/web/src/components/Sidebar.drag.test.ts b/apps/web/src/components/Sidebar.drag.test.ts index c757eca87aa4..4c1c006e91b6 100644 --- a/apps/web/src/components/Sidebar.drag.test.ts +++ b/apps/web/src/components/Sidebar.drag.test.ts @@ -621,6 +621,28 @@ describe("sidebar drag projection", () => { expect(result.get(sidebarMarkerId("snoozed-header"))).toEqual({ ...stationary, y: -46 }); }); + it("previews a time-ordered inbox drop at its time slot, above the Working shelf", () => { + const items = [ + pinnedHeader, + thread("p", "pinned"), + divider, + thread("a1", "active"), + thread("a2", "active"), + marker("working-header"), + thread("w", "working"), + settledHeader, + marker("settled-placeholder"), + ]; + const input = { items, settledOrder: [], settledExpanded: false }; + // By pointer, the unpinned row lands between a1 and a2. + expect(preview(input, "p", "a1").get("a2")?.y).toBe(0); + // By time, it lands below a2, and the shelf does not move. + const byTime = preview({ ...input, activeOrder: ["a1", "a2", "p"] }, "p", "a1"); + expect(byTime.get("a2")?.y).toBe(-83); + expect(byTime.get(sidebarMarkerId("working-header"))).toEqual(stationary); + expect(byTime.get("w")).toEqual(stationary); + }); + it("derives missing card geometry from the measured root scale", () => { const items = [ pinnedHeader, diff --git a/apps/web/src/components/Sidebar.drag.ts b/apps/web/src/components/Sidebar.drag.ts index bfd112d18998..4bc7bc6a8367 100644 --- a/apps/web/src/components/Sidebar.drag.ts +++ b/apps/web/src/components/Sidebar.drag.ts @@ -13,6 +13,11 @@ const stationary = { x: 0, y: 0, scaleX: 1, scaleY: 1 }; const hidden = { ...stationary, scaleY: 0 }; type ThreadItem = Extract; type Layout = Parameters[0]; +const isShelfHeader = (item: SidebarListItem | undefined) => + item?.kind === "marker" && + (item.marker === "working-header" || + item.marker === "snoozed-header" || + item.marker === "settled-header"); /** Keep the lifted card below the Pins label, including when Pins is empty. * The container rect follows scrolling; the offset is measured once at pickup. */ @@ -57,13 +62,11 @@ export function createSidebarCollisionDetection( if (pointer.x >= boundary.left && pointer.x <= boundary.right) { if (pointer.y < previousY && pointer.y <= boundary.bottom) boundarySection = "pinned"; else if (pointer.y > previousY && pointer.y >= boundary.top) boundarySection = "active"; - const nextHeader = - args.droppableContainers.find( - (container) => container.id === sidebarMarkerId("snoozed-header"), - ) ?? - args.droppableContainers.find( - (container) => container.id === sidebarMarkerId("settled-header"), - ); + const nextHeader = (["working-header", "snoozed-header", "settled-header"] as const) + .map((marker) => + args.droppableContainers.find((container) => container.id === sidebarMarkerId(marker)), + ) + .find((container) => container !== undefined); const activeBottom = nextHeader?.node.current?.getBoundingClientRect().top; if (boundarySection === "pinned" || (activeBottom != null && pointer.y < activeBottom)) { const target = collisions.find((collision) => { @@ -97,6 +100,8 @@ export function createSidebarCollisionDetection( export function createSidebarSortingStrategy(input: { items: readonly SidebarListItem[]; settledOrder: readonly string[]; + /** Time-ordered inbox (Working beta): where the lifted row would land. */ + activeOrder?: readonly string[]; settledExpanded: boolean; settledVisibleCount?: number; routeThreadKey?: string | null; @@ -121,6 +126,7 @@ export function createSidebarSortingStrategy(input: { const groups: Record = { pinned: [], active: [], + working: [], snoozed: [], settled: [], }; @@ -129,13 +135,13 @@ export function createSidebarSortingStrategy(input: { let headerScale: number | undefined; for (const [index, item] of items.entries()) { if (item.kind === "marker") { - if (item.marker === "settled-header" || item.marker === "snoozed-header") { + if (isShelfHeader(item)) { const height = rects[index]?.height; if (height) headerScale ??= height / 32; } continue; } - if (item.section === "pinned" || item.section === "active") + if (item.section === "pinned" || item.section === "active" || item.section === "working") cardHeight ??= rects[index]?.height; else slimHeight ??= rects[index]?.height; if (item.key !== active.key) groups[item.section].push(item); @@ -152,7 +158,7 @@ export function createSidebarSortingStrategy(input: { ? target.pinnedOrder : target.section === "settled" ? input.settledOrder - : target.activeOrder; + : (input.activeOrder ?? target.activeOrder); const ranks = new Map(order.map((key, index) => [key, index])); const rank = ranks.get(active.key) ?? Number.POSITIVE_INFINITY; const index = group.findIndex( @@ -180,6 +186,10 @@ export function createSidebarSortingStrategy(input: { projected.push(...groups.pinned); marker("pinned-divider"); section("active"); + if (items.some((item) => item.kind === "marker" && item.marker === "working-header")) { + marker("working-header"); + projected.push(...groups.working); + } if ( groups.snoozed.length > 0 || ((active.section !== "snoozed" || (input.snoozedThreadCount ?? 0) > 1) && @@ -194,7 +204,8 @@ export function createSidebarSortingStrategy(input: { const index = indices.get(sidebarListItemId(item)); const rect = index === undefined ? undefined : rects[index]; const fallback = - item.kind === "thread" && (item.section === "pinned" || item.section === "active") + item.kind === "thread" && + (item.section === "pinned" || item.section === "active" || item.section === "working") ? cardHeight : slimHeight; const moved = item.kind === "thread" && item.key === active.key; @@ -207,11 +218,7 @@ export function createSidebarSortingStrategy(input: { ? fallback : (rect?.height ?? fallback); }); - const firstShelf = items.findIndex( - (item) => - item.kind === "marker" && - (item.marker === "snoozed-header" || item.marker === "settled-header"), - ); + const firstShelf = items.findIndex(isShelfHeader); const shelfRect = rects[firstShelf]; const beforeShelf = rects[firstShelf - 1]; const lastRect = rects.at(-1); @@ -227,10 +234,7 @@ export function createSidebarSortingStrategy(input: { const result = items.map(() => hidden); let top = rects[0].top; for (const [projectedIndex, item] of projected.entries()) { - if ( - item.kind === "marker" && - (item.marker === "snoozed-header" || item.marker === "settled-header") - ) { + if (isShelfHeader(item)) { top += shelfSpace; shelfSpace = 0; } diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index 86cee77446f1..a4a606bb46c7 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -20,6 +20,7 @@ import { hasUnseenCompletion, isContextMenuPointerDown, isSidebarNestedLinkClick, + isSidebarThreadWorking, isTrailingDoubleClick, orderItemsByPreferredIds, resolveProjectStatusIndicator, @@ -32,6 +33,7 @@ import { shouldClearThreadSelectionOnMouseDown, shouldRecedeSidebarThread, sortLogicalProjectsForSidebar, + sortInboxThreadsByReturn, resolveSidebarDropTarget, pinOrderKeyBetween, planSidebarThreadDrop, @@ -2459,3 +2461,168 @@ describe("navigation after parking a thread", () => { }, ); }); + +describe("Working shelf (beta)", () => { + const session = { + threadId: ThreadId.make("thread-1"), + status: "running" as const, + providerName: "Codex", + providerInstanceId: ProviderInstanceId.make("codex"), + runtimeMode: DEFAULT_RUNTIME_MODE, + activeTurnId: "turn-1" as never, + lastError: null, + updatedAt: "2026-03-09T10:00:00.000Z", + }; + const idle = { + hasActionableProposedPlan: false, + hasPendingApprovals: false, + hasPendingUserInput: false, + interactionMode: "default" as const, + latestTurn: makeLatestTurn(), + session: { ...session, status: "ready" as const }, + }; + + it("folds away running and monitoring threads only", () => { + expect(isSidebarThreadWorking({ ...idle, session })).toBe(true); + expect(isSidebarThreadWorking({ ...idle, backgroundLiveness: "monitoring" })).toBe(true); + expect(isSidebarThreadWorking(idle)).toBe(false); + expect(isSidebarThreadWorking({ ...idle, session, hasPendingApprovals: true })).toBe(false); + expect(isSidebarThreadWorking({ ...idle, session, hasPendingUserInput: true })).toBe(false); + expect( + isSidebarThreadWorking({ + ...idle, + backgroundLiveness: "working", + session: { ...session, status: "error" as const, lastError: "boom" }, + }), + ).toBe(false); + }); + + it("keeps a ready plan in the inbox while background work runs", () => { + expect( + isSidebarThreadWorking({ + ...idle, + interactionMode: "plan", + hasActionableProposedPlan: true, + backgroundLiveness: "working", + }), + ).toBe(false); + }); + + describe("sortInboxThreadsByReturn", () => { + const thread = ( + id: string, + input: { createdAt: string; completedAt?: string | null; unsettledAt?: string }, + ) => ({ + id: ThreadId.make(id), + environmentId: localEnvironmentId, + createdAt: input.createdAt, + unsettledAt: input.unsettledAt ?? null, + latestTurn: + input.completedAt === undefined + ? null + : { ...makeLatestTurn({ completedAt: input.completedAt }), requestedAt: input.createdAt }, + }); + + it("puts the thread that finished last on top, whatever its age", () => { + const sorted = sortInboxThreadsByReturn([ + thread("new", { createdAt: "2026-03-09T11:00:00.000Z" }), + thread("old-finished-now", { + createdAt: "2026-03-01T09:00:00.000Z", + completedAt: "2026-03-09T12:00:00.000Z", + }), + thread("reopened", { + createdAt: "2026-03-02T09:00:00.000Z", + unsettledAt: "2026-03-09T11:30:00.000Z", + }), + ]); + expect(sorted.map((entry) => entry.id)).toEqual(["old-finished-now", "reopened", "new"]); + }); + + it("counts a return the server does not stamp, like an approval request", () => { + const waiting = thread("asks-approval", { + createdAt: "2026-03-09T09:00:00.000Z", + completedAt: null, + }); + const finished = thread("finished", { + createdAt: "2026-03-09T09:30:00.000Z", + completedAt: "2026-03-09T11:00:00.000Z", + }); + expect(sortInboxThreadsByReturn([finished, waiting]).map((entry) => entry.id)).toEqual([ + "finished", + "asks-approval", + ]); + expect( + sortInboxThreadsByReturn([finished, waiting], (entry) => + entry === waiting ? Date.parse("2026-03-09T11:05:00.000Z") : undefined, + ).map((entry) => entry.id), + ).toEqual(["asks-approval", "finished"]); + }); + }); + + describe("dragging", () => { + const marker = (name: SidebarListMarker): SidebarListItem => ({ kind: "marker", marker: name }); + const row = (key: string, section: SidebarSection): SidebarListItem => ({ + kind: "thread", + key, + section, + }); + // Pinned p1 | Active a1 a2 | Working w1 | Settled s1 + const items: readonly SidebarListItem[] = [ + marker("pinned-header"), + row("p1", "pinned"), + marker("pinned-divider"), + row("a1", "active"), + row("a2", "active"), + marker("working-header"), + row("w1", "working"), + marker("settled-header"), + row("s1", "settled"), + ]; + + it("never drops into the Working shelf, and keeps it out of the inbox order", () => { + expect(resolveSidebarDropTarget(items, "a1", "w1")).toBeNull(); + expect(resolveSidebarDropTarget(items, "p1", "a2")).toEqual({ + section: "active", + pinnedOrder: [], + activeOrder: ["a1", "a2", "p1"], + }); + expect(resolveSidebarDropVerb("active", "working")).toBeNull(); + }); + + it("only changes lifecycle when the inbox is time-ordered", () => { + const base = { + pinnedOrder: ["p1"], + pinnedKeysById: new Map([["p1", "m"]]), + activeOrder: ["a1", "a2"], + activeKeysById: new Map([ + ["a1", "f"], + ["a2", "t"], + ]), + activeTimeOrdered: true, + }; + expect( + planSidebarThreadDrop({ + ...base, + activeKey: "a1", + activeSection: "active", + target: { section: "active", pinnedOrder: ["p1"], activeOrder: ["a2", "a1"] }, + }), + ).toEqual({ kind: "none" }); + expect( + planSidebarThreadDrop({ + ...base, + activeKey: "p1", + activeSection: "pinned", + target: { section: "active", pinnedOrder: [], activeOrder: ["a1", "p1", "a2"] }, + }), + ).toEqual({ + kind: "move-active", + order: null, + assignments: [], + unpin: true, + unsettle: false, + unsnooze: false, + }); + }); + }); +}); diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 05664206105b..a63b728cd4fa 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -125,9 +125,10 @@ export const animateSidebarLayoutChanges: AnimateLayoutChanges = (args) => // the lifecycle action; Sidebar.drag previews the resulting layout. Pinned // and active threads keep the dragged position; settled threads use time // order. Snoozed rows can leave the shelf, but dropping into it is not -// supported because snoozing requires a wake time. +// supported because snoozing requires a wake time. The Working shelf (beta) +// follows live status, so it is neither a drag source nor a destination. -export type SidebarSection = "pinned" | "active" | "snoozed" | "settled"; +export type SidebarSection = "pinned" | "active" | "working" | "snoozed" | "settled"; /** Sortable ids: thread rows use their scoped key; structural items use a colon-free prefix: scoped thread keys always contain a colon. */ @@ -141,6 +142,7 @@ export type SidebarListMarker = | "settled-placeholder" /** The boundary between pinned and active rows. */ | "pinned-divider" + | "working-header" | "snoozed-header" | "settled-header"; @@ -158,7 +160,7 @@ export function sidebarListItemId(item: SidebarListItem): string { /** The section a slot belongs to, read off the markers around it: from the top down, everything before the pinned divider is pinned, then the - inbox until the snoozed header, the shelf until the settled header, + inbox until the first shelf header, each shelf until the next header, then settled. */ function sectionAtSidebarSlot(items: readonly SidebarListItem[], index: number): SidebarSection { let section: SidebarSection = "pinned"; @@ -166,6 +168,7 @@ function sectionAtSidebarSlot(items: readonly SidebarListItem[], index: number): const item = items[i]!; if (item.kind !== "marker") continue; if (item.marker === "pinned-divider") section = "active"; + else if (item.marker === "working-header") section = "working"; else if (item.marker === "snoozed-header") section = "snoozed"; else if (item.marker === "settled-header") section = "settled"; } @@ -173,7 +176,7 @@ function sectionAtSidebarSlot(items: readonly SidebarListItem[], index: number): } /** Resolve the destination section and manual order from an arrayMove across - * the separators. The snoozed shelf is never a destination. */ + * the separators. The working and snoozed shelves are never destinations. */ export type SidebarDropTarget = { readonly section: "pinned" | "active" | "settled"; readonly pinnedOrder: readonly string[]; @@ -191,14 +194,19 @@ export function resolveSidebarDropTarget( const moved = items.filter((_, index) => index !== activeIndex); moved.splice(overIndex, 0, items[activeIndex]!); const section = sectionAtSidebarSlot(moved, overIndex); - if (section === "snoozed") return null; + if (section === "working" || section === "snoozed") return null; const pinnedOrder: string[] = []; const activeOrder: string[] = []; let currentSection: SidebarSection = "pinned"; for (const item of moved) { if (item.kind === "marker") { if (item.marker === "pinned-divider") currentSection = "active"; - else if (item.marker === "snoozed-header" || item.marker === "settled-header") break; + else if ( + item.marker === "working-header" || + item.marker === "snoozed-header" || + item.marker === "settled-header" + ) + break; } else if (currentSection === "pinned") pinnedOrder.push(item.key); else activeOrder.push(item.key); } @@ -224,7 +232,8 @@ export type SidebarThreadDropPlan = } | { readonly kind: "move-active"; - readonly order: readonly string[]; + /** Null when the inbox is time-ordered: the drop has no placement. */ + readonly order: readonly string[] | null; readonly assignments: ReadonlyArray<{ readonly id: string; readonly orderKey: string }>; readonly unpin: boolean; readonly unsettle: boolean; @@ -234,14 +243,14 @@ export type SidebarThreadDropPlan = /** What dropping in `to` does to a thread lifted from `from`, for the badge on the lifted row. Null while reordering inside one section and for the - snoozed shelf, which cannot be a drop target. */ + working and snoozed shelves, which cannot be drop targets. */ export type SidebarDropVerb = "pin" | "unpin" | "settle" | "unsettle" | "wake"; export function resolveSidebarDropVerb( from: SidebarSection, to: SidebarSection | null, ): SidebarDropVerb | null { - if (to === null || to === from || to === "snoozed") return null; + if (to === null || to === from || to === "working" || to === "snoozed") return null; if (to === "pinned") return "pin"; if (to === "settled") return "settle"; if (from === "pinned") return "unpin"; @@ -264,6 +273,8 @@ export function planSidebarThreadDrop(input: { readonly activeOrder: readonly string[]; readonly activeKeysById: ReadonlyMap; readonly activeReorderableKeys?: ReadonlySet; + /** Working beta: the inbox sorts by time, so drops only change lifecycle. */ + readonly activeTimeOrdered?: boolean; }): SidebarThreadDropPlan { const { activeKey, @@ -283,6 +294,20 @@ export function planSidebarThreadDrop(input: { } switch (target.section) { case "active": { + // Like the settled tail: threads can enter a time-ordered inbox, but + // not be arranged inside it. + if (input.activeTimeOrdered) { + return activeSection === "active" + ? { kind: "none" } + : { + kind: "move-active", + order: null, + assignments: [], + unpin: activePinned, + unsettle: activeSettled, + unsnooze: activeSection === "snoozed", + }; + } const order = target.activeOrder; if ( activeSection === "active" && @@ -842,6 +867,16 @@ export function resolveSidebarThreadStatus(thread: SidebarThreadStatusInput): Si return "ready"; } +/** Working beta: threads busy with work that does not need the user fold into + the Working shelf. Approvals, questions, plan prompts, and failures stay + in the inbox. */ +export function isSidebarThreadWorking(thread: ThreadStatusInput): boolean { + const status = resolveSidebarThreadStatus(thread); + if (status !== "working" && status !== "monitoring") return false; + // A plan prompt outranks lingering background work, as in the status pill. + return resolveThreadStatusPill({ thread })?.label !== "Plan Ready"; +} + /** First VALID timestamp wins: `a ?? b` falls through on null, but a present- yet-malformed string must also fall through to the next candidate rather than sink the row to the epoch. */ @@ -950,6 +985,36 @@ export function reduceSidebarProjectScopeMenuState( } } +/** Working beta: the inbox lists threads newest first by when each last came + back to the user, so a thread that leaves the Working shelf lands on top. + `observedReturnAt` adds returns the server does not stamp, such as an + approval request mid-turn or background work ending. */ +export function sortInboxThreadsByReturn< + T extends Pick< + SidebarThreadSummary, + "id" | "environmentId" | "createdAt" | "unsettledAt" | "latestTurn" + >, +>(threads: readonly T[], observedReturnAt?: (thread: T) => number | undefined): T[] { + const timestamps = new Map( + threads.map((thread) => [ + thread, + Math.max( + toSortableTimestamp(thread.createdAt) ?? 0, + toSortableTimestamp(thread.unsettledAt ?? undefined) ?? 0, + toSortableTimestamp(thread.latestTurn?.requestedAt) ?? 0, + toSortableTimestamp(thread.latestTurn?.completedAt ?? undefined) ?? 0, + observedReturnAt?.(thread) ?? 0, + ), + ]), + ); + return [...threads].sort( + (left, right) => + timestamps.get(right)! - timestamps.get(left)! || + left.id.localeCompare(right.id) || + left.environmentId.localeCompare(right.environmentId), + ); +} + /** The timestamp a working thread's elapsed label counts from: the running turn's start (request time until adoption), falling back to the session's last transition when the turn projection lags behind. Malformed diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index 7b9e0e545d56..29849561efe2 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -166,6 +166,7 @@ import { firstValidTimestampMs, hasUnseenCompletion, isSidebarNestedLinkClick, + isSidebarThreadWorking, isTrailingDoubleClick, orderItemsByPreferredIds, planSidebarThreadDrop, @@ -183,6 +184,7 @@ import { resolveWorkingStartedAt, sidebarListItemId, sidebarMarkerId, + sortInboxThreadsByReturn, sortLogicalProjectsForSidebar, sortPinnedThreadsForSidebar, sortThreadsForSidebar, @@ -258,6 +260,39 @@ const SETTLED_TAIL_PAGE_COUNT = 25; // Fresh keys deliberately reset both shelves to collapsed for existing users. const SETTLED_SHELF_EXPANDED_KEY = "t3code:sidebar:settled-expanded"; const SNOOZED_SHELF_EXPANDED_KEY = "t3code:sidebar:snoozed-expanded"; +const WORKING_SHELF_EXPANDED_KEY = "t3code:sidebar:working-expanded"; + +// Working beta: when this client saw each thread leave the Working shelf. +// Module scope keeps the inbox order across routes that unmount the sidebar. +let lastWorkingThreadKeys: ReadonlySet | null = null; +const observedInboxReturns = new Map(); + +/** Stamps threads that stopped working since the last call. The first call + only takes a baseline, so mounting never reshuffles the inbox. Pass null + to reset when the beta is off. */ +function observeInboxReturns(threads: readonly EnvironmentThreadShell[] | null): void { + if (threads === null) { + lastWorkingThreadKeys = null; + observedInboxReturns.clear(); + return; + } + const working = new Set(); + const present = new Set(); + for (const thread of threads) { + const key = scopedThreadKey(scopeThreadRef(thread.environmentId, thread.id)); + present.add(key); + if (isSidebarThreadWorking(thread)) working.add(key); + } + // Drop deleted threads so the map stays bounded by the live thread list. + for (const key of observedInboxReturns.keys()) { + if (!present.has(key)) observedInboxReturns.delete(key); + } + const now = Date.now(); + for (const key of lastWorkingThreadKeys ?? []) { + if (present.has(key) && !working.has(key)) observedInboxReturns.set(key, now); + } + lastWorkingThreadKeys = working; +} function compactSidebarTimeLabel(label: string): string { if (label === "just now") return "now"; @@ -639,7 +674,7 @@ function SidebarDragBoundary(props: { // Shelf headers stay visible and keep their measured height while dragging. function SidebarSectionHeader(props: { - marker: "snoozed-header" | "settled-header"; + marker: "working-header" | "snoozed-header" | "settled-header"; label: string; className?: string; // While dragging, the settled header reads at full strength and takes the @@ -648,7 +683,13 @@ function SidebarSectionHeader(props: { isDropTarget?: boolean; toggle: { expanded: boolean; onToggle: () => void }; }) { - const snoozed = props.marker === "snoozed-header"; + const shelf = + props.marker === "working-header" + ? "working" + : props.marker === "snoozed-header" + ? "snoozed" + : "settled"; + const snoozed = shelf === "snoozed"; const className = cn( "flex h-full w-full items-center gap-2 px-2 text-left text-xs font-medium", snoozed ? "text-info-foreground" : "text-sidebar-muted-foreground/60", @@ -686,7 +727,7 @@ function SidebarSectionHeader(props: { type="button" onClick={props.toggle.onToggle} aria-expanded={props.toggle.expanded} - data-testid={`sidebar-${snoozed ? "snoozed" : "settled"}-shelf-toggle`} + data-testid={`sidebar-${shelf}-shelf-toggle`} className={cn(className, "cursor-pointer")} > {content} @@ -2184,6 +2225,7 @@ export default function Sidebar() { const confirmThreadArchive = useClientSettings((s) => s.confirmThreadArchive); const sidebarProjectSortOrder = useClientSettings((s) => s.sidebarProjectSortOrder); const timestampFormat = useClientSettings((s) => s.timestampFormat); + const workingShelfEnabled = useClientSettings((s) => s.sidebarWorkingShelfEnabled); const projectGroupingSettings = useClientSettings(selectProjectGroupingSettings); const { settleThread, @@ -2561,6 +2603,7 @@ export default function Sidebar() { draggableThreadKeys, activeReorderableThreadKeys, activeThreads, + workingThreads, snoozedThreads, settledThreads, snoozeNow, @@ -2577,8 +2620,14 @@ export default function Sidebar() { (scopedProjectKeys === null || scopedProjectKeys.has(`${thread.environmentId}:${thread.projectId}`)), ); + observeInboxReturns(workingShelfEnabled ? threads : null); const pinned: EnvironmentThreadShell[] = []; const active: EnvironmentThreadShell[] = []; + const working: EnvironmentThreadShell[] = []; + // Working beta: only inbox threads fold away. Pins stay where the user + // put them, and snoozed or settled threads keep their shelves. + const inbox = (thread: EnvironmentThreadShell) => + workingShelfEnabled && isSidebarThreadWorking(thread) ? working : active; const snoozed: EnvironmentThreadShell[] = []; const settled: EnvironmentThreadShell[] = []; const draggable = new Set(); @@ -2609,7 +2658,7 @@ export default function Sidebar() { ? pinned : optimisticDrop.section === "settled" ? settled - : active + : inbox(projected) ).push( optimisticDrop.clearsSnooze ? projected @@ -2623,7 +2672,7 @@ export default function Sidebar() { } else if (thread.pinnedAt != null) { pinned.push(thread); } else { - active.push(thread); + inbox(thread).push(thread); } } // One shared rule on every platform (see sortPinnedThreadsByOrderKey): @@ -2632,7 +2681,13 @@ export default function Sidebar() { // sort, or mixed-version fleets would render different pinned orders on // web and mobile from the same data. const sortedPinned = sortPinnedThreadsForSidebar(pinned); - const sortedActive = sortThreadsForSidebar(active); + const sortedActive = workingShelfEnabled + ? sortInboxThreadsByReturn(active, (thread) => + observedInboxReturns.get( + scopedThreadKey(scopeThreadRef(thread.environmentId, thread.id)), + ), + ) + : sortThreadsForSidebar(active); return { pinnedThreads: optimisticDrop?.section !== "pinned" || optimisticDrop.order === null @@ -2652,6 +2707,8 @@ export default function Sidebar() { preferredIds: optimisticDrop.order, getId: (thread) => scopedThreadKey(scopeThreadRef(thread.environmentId, thread.id)), }), + // Newest work first, by the same clock as the inbox. + workingThreads: sortInboxThreadsByReturn(working), // Soonest wake first: "what comes back next" is the shelf's question. snoozedThreads: snoozed.toSorted( (left, right) => @@ -2661,15 +2718,29 @@ export default function Sidebar() { settledThreads: sortSettledThreads(settled), snoozeNow: preciseNow, }; - }, [nowMinute, optimisticDrop, scopedProjectKeys, serverConfigs, snoozeWakeTick, threads]); + }, [ + nowMinute, + optimisticDrop, + scopedProjectKeys, + serverConfigs, + snoozeWakeTick, + threads, + workingShelfEnabled, + ]); const threadSearchInputRef = useRef(null); const [threadSearchQuery, setThreadSearchQuery] = useState(""); const [activeSearchResultIndex, setActiveSearchResultIndex] = useState(0); const isSearchingThreads = threadSearchQuery.trim().length > 0; const searchableThreads = useMemo( - () => [...pinnedThreads, ...activeThreads, ...snoozedThreads, ...settledThreads], - [activeThreads, pinnedThreads, settledThreads, snoozedThreads], + () => [ + ...pinnedThreads, + ...activeThreads, + ...workingThreads, + ...snoozedThreads, + ...settledThreads, + ], + [activeThreads, pinnedThreads, settledThreads, snoozedThreads, workingThreads], ); const searchEnvironmentIds = useMemo( () => @@ -2805,9 +2876,43 @@ export default function Sidebar() { return routeThread === undefined ? EMPTY_THREADS : [routeThread]; }, [routeThreadKey, snoozedShelfExpanded, snoozedThreads]); + // The Working shelf (beta) collapses the same way, with the same route + // exception: sending a message folds the open thread into the shelf, and + // its row must stay visible there. + const [workingShelfExpanded, setWorkingShelfExpanded] = useLocalStorage( + WORKING_SHELF_EXPANDED_KEY, + false, + Schema.Boolean, + ); + const toggleWorkingShelf = useCallback( + () => setWorkingShelfExpanded((value) => !value), + [setWorkingShelfExpanded], + ); + const visibleWorkingThreads = useMemo(() => { + if (workingShelfExpanded) return workingThreads; + if (routeThreadKey === null) return EMPTY_THREADS; + const routeThread = workingThreads.find( + (thread) => + scopedThreadKey(scopeThreadRef(thread.environmentId, thread.id)) === routeThreadKey, + ); + return routeThread === undefined ? EMPTY_THREADS : [routeThread]; + }, [routeThreadKey, workingShelfExpanded, workingThreads]); + const orderedThreads = useMemo( - () => [...pinnedThreads, ...activeThreads, ...visibleSnoozedThreads, ...renderedSettledThreads], - [pinnedThreads, activeThreads, visibleSnoozedThreads, renderedSettledThreads], + () => [ + ...pinnedThreads, + ...activeThreads, + ...visibleWorkingThreads, + ...visibleSnoozedThreads, + ...renderedSettledThreads, + ], + [ + pinnedThreads, + activeThreads, + visibleWorkingThreads, + visibleSnoozedThreads, + renderedSettledThreads, + ], ); const orderedThreadKeys = useMemo( () => @@ -3230,10 +3335,11 @@ export default function Sidebar() { }; add(pinnedThreads, "pinned"); add(activeThreads, "active"); + add(workingThreads, "working"); add(snoozedThreads, "snoozed"); add(settledThreads, "settled"); return map; - }, [activeThreads, pinnedThreads, settledThreads, snoozedThreads]); + }, [activeThreads, pinnedThreads, settledThreads, snoozedThreads, workingThreads]); const pinnedKeys = useMemo( () => pinnedThreads.map((thread) => @@ -3400,6 +3506,7 @@ export default function Sidebar() { if ( pinnedThreads.length + activeThreads.length + + workingThreads.length + snoozedThreads.length + settledThreads.length === 0 @@ -3413,6 +3520,10 @@ export default function Sidebar() { const activeRows = rowsOf(activeThreads, "active"); items.push({ kind: "marker", marker: "active-placeholder" }); items.push(...activeRows); + if (workingThreads.length > 0) { + items.push({ kind: "marker", marker: "working-header" }); + items.push(...rowsOf(visibleWorkingThreads, "working")); + } if (snoozedThreads.length > 0) { items.push({ kind: "marker", marker: "snoozed-header" }); items.push(...rowsOf(visibleSnoozedThreads, "snoozed")); @@ -3429,6 +3540,8 @@ export default function Sidebar() { settledThreads.length, snoozedThreads.length, visibleSnoozedThreads, + visibleWorkingThreads, + workingThreads.length, ]); useEffect(() => { if ( @@ -3489,18 +3602,35 @@ export default function Sidebar() { applySidebarThreadDrop(thread, "settled", dragState.occurredAt), ]).map(key); }, [dragState, settledThreads, threadByKey]); + // Working beta: the inbox is time-ordered too, so the preview shows the + // slot a drop will land in, not the slot under the pointer. + const draggedActiveOrder = useMemo(() => { + const thread = dragState === null ? undefined : threadByKey.get(dragState.activeKey); + if (!workingShelfEnabled || dragState === null || thread === undefined) return undefined; + const key = (candidate: EnvironmentThreadShell) => + scopedThreadKey(scopeThreadRef(candidate.environmentId, candidate.id)); + return sortInboxThreadsByReturn( + [ + ...activeThreads.filter((candidate) => key(candidate) !== dragState.activeKey), + applySidebarThreadDrop(thread, "active", dragState.occurredAt), + ], + (candidate) => observedInboxReturns.get(key(candidate)), + ).map(key); + }, [activeThreads, dragState, threadByKey, workingShelfEnabled]); const sidebarSortingStrategy = useMemo( () => createSidebarSortingStrategy({ items: sidebarListItems, boundaryLabelHeight: SIDEBAR_DRAG_LABEL_HEIGHT, settledOrder: draggedSettledOrder, + ...(draggedActiveOrder === undefined ? {} : { activeOrder: draggedActiveOrder }), settledExpanded: settledShelfExpanded, settledVisibleCount, routeThreadKey, snoozedThreadCount: snoozedThreads.length, }), [ + draggedActiveOrder, draggedSettledOrder, routeThreadKey, settledShelfExpanded, @@ -3556,6 +3686,7 @@ export default function Sidebar() { activeOrder: activeKeys, activeKeysById, activeReorderableKeys: activeReorderableThreadKeys, + activeTimeOrdered: workingShelfEnabled, }).kind !== "none" ); }, @@ -3577,6 +3708,7 @@ export default function Sidebar() { pinnedKeys, sidebarListItems, threadByKey, + workingShelfEnabled, ]); const handleThreadDragEnd = useCallback( (event: DragEndEvent) => { @@ -3604,6 +3736,7 @@ export default function Sidebar() { activeOrder: activeKeys, activeKeysById, activeReorderableKeys: activeReorderableThreadKeys, + activeTimeOrdered: workingShelfEnabled, }); if (plan.kind === "none") return; if (plan.kind === "settle" && settlingThreadKeysRef.current.has(activeKey)) return; @@ -3737,6 +3870,7 @@ export default function Sidebar() { unpinThread, unsettleThread, unsnoozeThread, + workingShelfEnabled, ], ); // One snooze per thread at a time — same double-dispatch guard as settle. @@ -4717,7 +4851,9 @@ export default function Sidebar() { // row: every other thread is a full card. Density comes // from users (or the auto rules) actually parking work, // not from the sidebar second-guessing what still matters. - const isCard = section === "active" || section === "pinned"; + // Working rows stay cards so their live status shows. + const isCard = + section === "active" || section === "pinned" || section === "working"; const rowVariant = isCard ? "card" : "slim"; return ( , ); break; + case "working-header": + items.push( + , + ); + break; case "snoozed-header": items.push( void) { DEFAULT_UNIFIED_SETTINGS.sidebarProjectGroupingMode ? ["Project Grouping"] : []), + ...(settings.sidebarWorkingShelfEnabled !== + DEFAULT_UNIFIED_SETTINGS.sidebarWorkingShelfEnabled + ? ["Working section"] + : []), ...(settings.sidebarAutoSettleAfterDays !== DEFAULT_UNIFIED_SETTINGS.sidebarAutoSettleAfterDays ? ["Auto-settle inactive threads"] @@ -684,6 +688,7 @@ export function useSettingsRestore(onRestored?: () => void) { settings.sidebarAutoSettleAfterDays, settings.sidebarAutoSettleOnMerge, settings.sidebarProjectGroupingMode, + settings.sidebarWorkingShelfEnabled, settings.sidebarThreadPreviewCount, settings.showSkillsInSlashMenu, settings.timestampFormat, @@ -781,6 +786,7 @@ export function useSettingsRestore(onRestored?: () => void) { panelAnimationDurationMs: DEFAULT_UNIFIED_SETTINGS.panelAnimationDurationMs, sidebarThreadPreviewCount: DEFAULT_UNIFIED_SETTINGS.sidebarThreadPreviewCount, sidebarProjectGroupingMode: DEFAULT_UNIFIED_SETTINGS.sidebarProjectGroupingMode, + sidebarWorkingShelfEnabled: DEFAULT_UNIFIED_SETTINGS.sidebarWorkingShelfEnabled, sidebarAutoSettleAfterDays: DEFAULT_UNIFIED_SETTINGS.sidebarAutoSettleAfterDays, sidebarAutoSettleOnMerge: DEFAULT_UNIFIED_SETTINGS.sidebarAutoSettleOnMerge, responseStreamingMode: DEFAULT_UNIFIED_SETTINGS.responseStreamingMode, @@ -2269,6 +2275,33 @@ export function GeneralSettingsPanel() { } /> + + updateSettings({ + sidebarWorkingShelfEnabled: DEFAULT_UNIFIED_SETTINGS.sidebarWorkingShelfEnabled, + }) + } + /> + ) : null + } + control={ + + updateSettings({ sidebarWorkingShelfEnabled: Boolean(checked) }) + } + aria-label="Working section (beta)" + /> + } + /> + {supportsAutoSettlement ? ( <> Date: Thu, 1 Oct 2026 20:20:40 -0700 Subject: [PATCH 21/32] fix(web): PR checks status collapses to its icon instead of wrapping (#14700) --- .../pullRequest/PullRequestDetailPanel.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx b/apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx index 1b42fdd4481a..5c82e03aa8ea 100644 --- a/apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx +++ b/apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx @@ -1517,6 +1517,8 @@ export function PullRequestDetailPanel({ const statePresentation = detail ? resolvePullRequestState({ state: detail.state, isDraft: detail.isDraft }) : null; + const showsApproveWorkflows = + workflowApprovalsRequired > 0 && !checksStale && can("approve-workflows"); const checksSummary = checksStale ? checksState === null ? "No checks reported" @@ -2551,8 +2553,13 @@ export function PullRequestDetailPanel({ ))} {tab === "summary" ? ( - - {workflowApprovalsRequired > 0 && !checksStale && can("approve-workflows") ? ( + + {showsApproveWorkflows ? ( ) : ( {checksState !== null ? ( @@ -2601,7 +2608,7 @@ export function PullRequestDetailPanel({ ) : ( )} - {checksSummary} + {checksSummary} )} From fa6262db3107a4c95b6ff611113e6fa0753e5948 Mon Sep 17 00:00:00 2001 From: "t3-code[bot]" <269035359+t3-code[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:32:03 -0300 Subject: [PATCH 22/32] fix: remove outdated restart setting update advice (#14710) Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> Co-authored-by: maria <254055478+maria-rcks@users.noreply.github.com> --- apps/web/src/components/settings/SettingsPanels.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/settings/SettingsPanels.tsx b/apps/web/src/components/settings/SettingsPanels.tsx index bd5922df2a51..d44f64356b52 100644 --- a/apps/web/src/components/settings/SettingsPanels.tsx +++ b/apps/web/src/components/settings/SettingsPanels.tsx @@ -2839,7 +2839,7 @@ export function GeneralSettingsPanel() { {...searchableSetting("continue-threads-after-server-update")} serverScoped settingKeys={["continueThreadsAfterServerUpdate"]} - description="Automatically resume interrupted threads after an update, crash, or machine restart on the selected environments. Update older servers first." + description="Automatically resume interrupted threads after an update, crash, or machine restart on the selected environments." status={ !supportsRestartContinuation ? "All selected connected environments must support restart continuation." From 20012ebd80b06a4c10ab0e78893822e7f873b2a8 Mon Sep 17 00:00:00 2001 From: Igor Makowski <56691628+Mnigos@users.noreply.github.com> Date: Fri, 2 Oct 2026 05:33:36 +0200 Subject: [PATCH 23/32] fix(web): keep the terminal toggle clear of the last header action (#13426) --- apps/web/src/components/ChatView.tsx | 7 ++++++- apps/web/src/components/chat/ChatHeader.tsx | 8 +++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index db13c8f21c80..a32c1473cda7 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -9516,7 +9516,12 @@ export default function ChatView(props: ChatViewProps) { "flex shrink-0", panelAnimationsActive && "motion-safe:transition-opacity motion-safe:duration-(--panel-animation-duration) motion-safe:ease-out", - rightPanelOpen ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0", + // Closed, the control leaves the flex flow so the cluster is only as wide as the two + // toggles the header reserves room for; anchored to the cluster's left edge, it fades + // out where it stood rather than over the terminal toggle. + rightPanelOpen + ? "pointer-events-auto opacity-100" + : "pointer-events-none absolute right-full mr-1 opacity-0", )} inert={!rightPanelOpen} > diff --git a/apps/web/src/components/chat/ChatHeader.tsx b/apps/web/src/components/chat/ChatHeader.tsx index bbe014ddbd06..92f615538f2d 100644 --- a/apps/web/src/components/chat/ChatHeader.tsx +++ b/apps/web/src/components/chat/ChatHeader.tsx @@ -492,9 +492,11 @@ export const ChatHeader = memo(function ChatHeader({ data-chat-header-actions className={cn( "flex shrink-0 items-center justify-end gap-2 @3xl/header-actions:gap-3", - // Reserve two panel toggles plus their 4px gaps and 1px edge inset. - // The page header adds 8px more right padding at sm. - rightPanelOpen ? "pr-0" : "pr-18.25 sm:pr-14.25", + // Reserve two panel toggles (32px, 28px at sm) with their 4px gap and 1px edge inset, + // plus the same gap the actions keep between themselves (gap-2, gap-3 at @3xl) so the + // terminal toggle does not sit against the last action. The page header adds 8px more + // right padding at sm. + rightPanelOpen ? "pr-0" : "pr-19.25 sm:pr-15.25 @3xl/header-actions:pr-16.25", "[[data-panel-animations=true]_&]:motion-safe:transition-[padding-right] [[data-panel-animations=true]_&]:motion-safe:duration-(--panel-animation-duration) [[data-panel-animations=true]_&]:motion-safe:ease-out", )} > From 2731929610ecb64617ff5e066980302da328f658 Mon Sep 17 00:00:00 2001 From: Chris Deeming Date: Fri, 2 Oct 2026 05:37:45 +0100 Subject: [PATCH 24/32] fix(web): group composer undo the way the Lexical composer did (#14674) --- .../components/ComposerPromptEditorTiptap.tsx | 49 +++++- apps/web/src/composer-undo-grouping.test.ts | 143 ++++++++++++++++++ apps/web/src/composer-undo-grouping.ts | 64 ++++++++ 3 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 apps/web/src/composer-undo-grouping.test.ts create mode 100644 apps/web/src/composer-undo-grouping.ts diff --git a/apps/web/src/components/ComposerPromptEditorTiptap.tsx b/apps/web/src/components/ComposerPromptEditorTiptap.tsx index c8866e7fc413..aff70b58b1b8 100644 --- a/apps/web/src/components/ComposerPromptEditorTiptap.tsx +++ b/apps/web/src/components/ComposerPromptEditorTiptap.tsx @@ -56,6 +56,12 @@ import { serializeEditorDoc, type SkillMeta, } from "~/composer-rich-text-doc"; +import { + COMPOSER_UNDO_GROUP_DELAY, + type ComposerChangeKind, + groupUndoByChangeKind, + markAsClipboardEdit, +} from "~/composer-undo-grouping"; import { collectInlineContextIds } from "~/lib/composerContextReferences"; import { cn, isMacPlatform } from "~/lib/utils"; import { basenameOfPath } from "~/pierre-icons"; @@ -586,6 +592,26 @@ export function ComposerPromptEditorTiptap(props: ComposerPromptEditorProps) { ); } +/** + * Starts a new undo step when the kind of change switches (typing, deleting, + * a paste or a store rewrite), the way the Lexical composer grouped undo. + * Runs as dispatch middleware because the grouping has to be decided before + * the history plugin applies the transaction. + */ +const ComposerUndoGroupingExtension = Extension.create< + Record, + { previous: ComposerChangeKind | null } +>({ + name: "composer-undo-grouping", + addStorage() { + return { previous: null }; + }, + dispatchTransaction({ transaction, next }) { + this.storage.previous = groupUndoByChangeKind(transaction, this.storage.previous); + next(transaction); + }, +}); + function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { const { value, @@ -798,9 +824,11 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { gapcursor: false, trailingNode: false, code: false, + undoRedo: { newGroupDelay: COMPOSER_UNDO_GROUP_DELAY }, // Plain mode has no marks: typed markers stay literal characters. ...(richText ? {} : { bold: false, italic: false, strike: false }), }), + ComposerUndoGroupingExtension, ComposerMentionExtension, ComposerSkillExtension, ComposerCitationExtension, @@ -1048,7 +1076,16 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { const editorInstance = editorHolder.current; if (editorInstance) { insertMarkdownParagraphs(text, skillLabelFor, { styling: richText }, (content) => { - editorInstance.commands.insertContent(content); + // Tagged on the same transaction insertContent builds, so the + // paste is one undo step of its own. + editorInstance + .chain() + .command(({ tr }) => { + markAsClipboardEdit(tr, "paste"); + return true; + }) + .insertContent(content) + .run(); }); scrollTiptapCaretIntoView(editorInstance); } @@ -1309,7 +1346,15 @@ function ComposerPromptEditorTiptapInner(props: ComposerPromptEditorProps) { clipboardData.setData("text/html", encodeComposerContextClipboardHtml(text, fragment)); } if (cut) { - editor.chain().focus().deleteSelection().run(); + editor + .chain() + .focus() + .command(({ tr }) => { + markAsClipboardEdit(tr, "cut"); + return true; + }) + .deleteSelection() + .run(); } }, [editor], diff --git a/apps/web/src/composer-undo-grouping.test.ts b/apps/web/src/composer-undo-grouping.test.ts new file mode 100644 index 000000000000..e65b18579e3a --- /dev/null +++ b/apps/web/src/composer-undo-grouping.test.ts @@ -0,0 +1,143 @@ +import { getSchema } from "@tiptap/core"; +import { history, undo } from "@tiptap/pm/history"; +import { EditorState, TextSelection, type Transaction } from "@tiptap/pm/state"; +import StarterKit from "@tiptap/starter-kit"; +import { describe, expect, it } from "vite-plus/test"; + +import { + COMPOSER_UNDO_GROUP_DELAY, + type ComposerChangeKind, + groupUndoByChangeKind, + markAsClipboardEdit, +} from "./composer-undo-grouping"; + +const schema = getSchema([StarterKit]); + +/** + * A composer-shaped editor state with the real history plugin, dispatching + * through the same grouping rule the composer's extension applies. Keystrokes + * land 80ms apart unless a gap says otherwise. + */ +function composer(text = "") { + let clock = 0; + let previous: ComposerChangeKind | null = null; + let state = EditorState.create({ + schema, + doc: schema.node("doc", null, [ + schema.node("paragraph", null, text ? [schema.text(text)] : []), + ]), + plugins: [history({ newGroupDelay: COMPOSER_UNDO_GROUP_DELAY })], + }); + const dispatch = (tr: Transaction) => { + tr.setTime(clock); + previous = groupUndoByChangeKind(tr, previous); + state = state.apply(tr); + }; + dispatch(state.tr.setSelection(TextSelection.atEnd(state.doc))); + const api = { + text: () => state.doc.textContent, + wait: (ms: number) => ((clock += ms), api), + type: (s: string, gap = 80) => { + for (const ch of s) { + clock += gap; + dispatch(state.tr.insertText(ch)); + } + return api; + }, + backspace: (n: number) => { + for (let i = 0; i < n; i += 1) { + clock += 80; + const at = state.selection.from; + dispatch(state.tr.delete(at - 1, at)); + } + return api; + }, + /** + * The transaction the composer's `handlePaste` dispatches: a plain insert, + * tagged by `markAsClipboardEdit`. ProseMirror's own paste path would tag + * it, but the composer takes every text paste before that path runs. + */ + paste: (s: string) => { + clock += 80; + dispatch(markAsClipboardEdit(state.tr.insertText(s), "paste")); + return api; + }, + /** The composer's cut handler: a plain delete of the selection, tagged. */ + cut: (n: number) => { + clock += 80; + const at = state.selection.from; + dispatch(markAsClipboardEdit(state.tr.delete(at - n, at), "cut")); + return api; + }, + /** A store-driven rewrite: autocomplete inserting a chip, list continuation. */ + rewrite: (next: string) => { + clock += 80; + dispatch( + state.tr.replaceWith( + 0, + state.doc.content.size, + schema.node("paragraph", null, [schema.text(next)]), + ), + ); + dispatch(state.tr.setSelection(TextSelection.atEnd(state.doc))); + return api; + }, + /** IME input replaces its own range on every keystroke. */ + compose: (s: string) => { + const start = state.selection.from; + for (let i = 1; i <= s.length; i += 1) { + clock += 80; + dispatch( + state.tr.insertText(s.slice(0, i), start, start + i - 1).setMeta("composition", 1), + ); + } + return api; + }, + undo: () => (undo(state, dispatch), api), + }; + return api; +} + +describe("composer undo grouping", () => { + it("keeps a continuous run of typing as one step", () => { + expect(composer().type("hello world").undo().text()).toBe(""); + }); + + it("starts a new step when typing turns into deleting, and back", () => { + const editor = composer().type("hello world").backspace(5).type("there"); + expect(editor.text()).toBe("hello there"); + expect(editor.undo().text()).toBe("hello "); + expect(editor.undo().text()).toBe("hello world"); + expect(editor.undo().text()).toBe(""); + }); + + it("gives a store rewrite its own step, and typing after it another", () => { + const editor = composer("draft ").type("one").rewrite("draft one @chip ").type("then"); + expect(editor.undo().text()).toBe("draft one @chip "); + expect(editor.undo().text()).toBe("draft one"); + expect(editor.undo().text()).toBe("draft "); + }); + + it("gives a paste its own step", () => { + const editor = composer().type("see ").paste("pasted text").type(" ok"); + expect(editor.undo().text()).toBe("see pasted text"); + expect(editor.undo().text()).toBe("see "); + }); + + it("gives a cut its own step between deletions", () => { + const editor = composer().type("hello world").backspace(1).cut(3).backspace(1); + expect(editor.text()).toBe("hello "); + expect(editor.undo().text()).toBe("hello w"); + expect(editor.undo().text()).toBe("hello worl"); + expect(editor.undo().text()).toBe("hello world"); + }); + + it("keeps IME composition as one run of typing", () => { + expect(composer().type("go ").compose("にほん").undo().text()).toBe(""); + }); + + it("merges typing across a short pause and splits it across a long one", () => { + expect(composer().type("hello").wait(700).type(" world").undo().text()).toBe(""); + expect(composer().type("hello").wait(1100).type(" world").undo().text()).toBe("hello"); + }); +}); diff --git a/apps/web/src/composer-undo-grouping.ts b/apps/web/src/composer-undo-grouping.ts new file mode 100644 index 000000000000..f895b8d7afc6 --- /dev/null +++ b/apps/web/src/composer-undo-grouping.ts @@ -0,0 +1,64 @@ +import { closeHistory, isHistoryTransaction } from "@tiptap/pm/history"; +import type { Transaction } from "@tiptap/pm/state"; +import { ReplaceStep } from "@tiptap/pm/transform"; + +/** + * Undo grouping matching the Lexical composer it replaced. + * + * ProseMirror's history only starts a new undo step after a pause or when an + * edit is not next to the last one, so typing, backspacing and typing again + * without pausing is one step, and a store rewrite of the whole document + * (autocomplete inserting a chip, list continuation) makes every later edit + * "adjacent" and joins it. Lexical instead started a new step whenever the + * kind of change switched, and after one second without changes. + */ +export const COMPOSER_UNDO_GROUP_DELAY = 1000; + +export type ComposerChangeKind = "insert" | "delete" | "other"; + +/** + * Tags a transaction as a paste or cut, so it becomes its own undo step. + * ProseMirror tags these itself only on its built-in clipboard paths; the + * composer's `handlePaste` and cut handler replace those paths, so each of + * their dispatches must call this, or the change merges with the typing or + * deleting around it. + */ +export function markAsClipboardEdit(tr: Transaction, event: "paste" | "cut"): Transaction { + return tr.setMeta("uiEvent", event); +} + +function changeKindOf(tr: Transaction): ComposerChangeKind | null { + if (!tr.docChanged) return null; + const uiEvent = tr.getMeta("uiEvent"); + if (uiEvent === "paste" || uiEvent === "drop" || uiEvent === "cut") return "other"; + // IME input replaces its own range on each keystroke; it is still typing. + if (tr.getMeta("composition") != null) return "insert"; + let kind: ComposerChangeKind | null = null; + for (const step of tr.steps) { + if (!(step instanceof ReplaceStep)) return "other"; + const inserts = step.slice.size > 0; + const deletes = step.to > step.from; + const stepKind = inserts && !deletes ? "insert" : deletes && !inserts ? "delete" : "other"; + if (kind !== null && kind !== stepKind) return "other"; + kind = stepKind; + } + return kind; +} + +/** + * Closes the current undo step before `tr` when its kind of change differs + * from the last one, or when it is a one-off change such as a paste or a + * store rewrite, and returns the kind to remember for the next transaction. + * Undo and redo themselves count as one-off, so typing after them starts a + * fresh step. Must run before the transaction is applied. + */ +export function groupUndoByChangeKind( + tr: Transaction, + previous: ComposerChangeKind | null, +): ComposerChangeKind | null { + if (isHistoryTransaction(tr)) return "other"; + const kind = changeKindOf(tr); + if (kind === null) return previous; + if (previous !== null && (kind !== previous || kind === "other")) closeHistory(tr); + return kind; +} From 3e60fecf39f37faaca9bdf37e64b7a58229ea547 Mon Sep 17 00:00:00 2001 From: shivam <91240327+shivamhwp@users.noreply.github.com> Date: Fri, 2 Oct 2026 10:34:17 +0530 Subject: [PATCH 25/32] fix(desktop): markdown pages no longer render invisible in the dark-mode browser (#14601) Co-authored-by: PR Batch Tester Co-authored-by: Claude Opus 5.5 (1M context) --- apps/desktop/src/preview/Manager.test.ts | 16 +++++++++++++++- apps/desktop/src/preview/Manager.ts | 13 +++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src/preview/Manager.test.ts b/apps/desktop/src/preview/Manager.test.ts index d3f6971b820b..95197d8916a0 100644 --- a/apps/desktop/src/preview/Manager.test.ts +++ b/apps/desktop/src/preview/Manager.test.ts @@ -1601,7 +1601,7 @@ describe("PreviewManager", () => { ), ); - effectIt.effect("emulates prefers-color-scheme and re-applies it across webview swaps", () => + effectIt.effect("re-applies opaque base and color scheme across webview swaps", () => withManager((manager) => Effect.gen(function* () { const makeWebContents = (id: number) => { @@ -1650,6 +1650,16 @@ describe("PreviewManager", () => { yield* manager.registerWebview("tab_scheme", 42); yield* Effect.yieldNow; + // Guests start with a transparent base; dark-scheme pages need an opaque + // one or Chromium skips their dark canvas. + const opaqueBase = { + color: { r: 255, g: 255, b: 255, a: 1 }, + }; + expect(first.sendCommand).toHaveBeenCalledWith( + "Emulation.setDefaultBackgroundColorOverride", + opaqueBase, + ); + yield* manager.setColorScheme("tab_scheme", "dark"); expect(first.sendCommand).toHaveBeenCalledWith("Emulation.setEmulatedMedia", { @@ -1662,6 +1672,10 @@ describe("PreviewManager", () => { yield* manager.registerWebview("tab_scheme", 43); yield* Effect.yieldNow; + expect(replacement.sendCommand).toHaveBeenCalledWith( + "Emulation.setDefaultBackgroundColorOverride", + opaqueBase, + ); expect(replacement.sendCommand).toHaveBeenCalledWith("Emulation.setEmulatedMedia", { features: [{ name: "prefers-color-scheme", value: "dark" }], }); diff --git a/apps/desktop/src/preview/Manager.ts b/apps/desktop/src/preview/Manager.ts index cc1a8f524dc8..4195bdffff6a 100644 --- a/apps/desktop/src/preview/Manager.ts +++ b/apps/desktop/src/preview/Manager.ts @@ -1418,6 +1418,19 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function ), { concurrency: "unbounded", discard: true }, ); + // Electron gives `` guests a transparent base background, and + // Chromium only paints a dark canvas for dark color-scheme pages over an + // opaque base. Without this, dark-scheme pages with no background of + // their own (text/plain, e.g. .md files) render white text on white. + // White matches the webview's existing white backing, so light pages look + // the same; Chromium still swaps in its dark canvas for dark-scheme pages. + yield* attemptPromise( + { operation: "initializeDebugger.defaultBackground", webContentsId: wc.id }, + () => + wcDebugger.sendCommand("Emulation.setDefaultBackgroundColorOverride", { + color: { r: 255, g: 255, b: 255, a: 1 }, + }), + ); return [ control, replaceMap(sessions, (copy) => { From 39405f1992b4d1264730138b0fe31e07d66df4f4 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 22:18:18 -0700 Subject: [PATCH 26/32] fix(mobile): one No project row at the top of the project picker (#14532) Co-authored-by: Claude Opus 5.5 (1M context) --- .../threads/NewTaskContextPickerScreens.tsx | 49 +++++- .../features/threads/NewTaskDraftScreen.tsx | 64 +++++--- .../features/threads/NewTaskRouteScreen.tsx | 139 ++++++++---------- .../threads/new-task-flow-provider.tsx | 49 +++++- 4 files changed, 196 insertions(+), 105 deletions(-) diff --git a/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx b/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx index b30175b5b0de..28e49cbdb5b9 100644 --- a/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx +++ b/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx @@ -1,6 +1,8 @@ import { MaterialListRow } from "../../components/MaterialListRow"; import type { VcsRef } from "@t3tools/client-runtime/state/vcs"; -import { resolveEnvironmentMachineKind } from "@t3tools/contracts"; +import { type EnvironmentId, resolveEnvironmentMachineKind } from "@t3tools/contracts"; +import * as Cause from "effect/Cause"; +import { AsyncResult } from "effect/unstable/reactivity"; import { LegendList } from "@legendapp/list/react-native"; import { isAtomCommandInterrupted, @@ -28,7 +30,8 @@ import { EnvironmentMachineSymbol } from "../../components/EnvironmentMachineSym import { ThemedSwitch } from "../../components/ThemedSwitch"; import { cn } from "../../lib/cn"; import { NativeHeaderToolbar, NativeStackScreenOptions } from "../../native/StackHeader"; -import { useServerConfigs } from "../../state/entities"; +import { useServerConfigs, waitForProject } from "../../state/entities"; +import { projectEnvironment } from "../../state/projects"; import { useAtomCommand } from "../../state/use-atom-command"; import { vcsEnvironment } from "../../state/vcs"; import { @@ -203,6 +206,38 @@ export function NewTaskEnvironmentPickerRouteScreen() { const navigation = useNavigation(); const insets = useSafeAreaInsets(); const serverConfigs = useServerConfigs(); + const ensureScratch = useAtomCommand(projectEnvironment.ensureScratch, { + reportFailure: false, + }); + const [movingToEnvironmentId, setMovingToEnvironmentId] = useState(null); + + // A thread without a project moves to the other machine's own Scratch + // project, which is created there first if it does not exist yet. + async function moveScratchDraft(environmentId: EnvironmentId): Promise { + setMovingToEnvironmentId(environmentId); + try { + const result = await ensureScratch({ environmentId, input: {} }); + if (AsyncResult.isFailure(result)) { + const error = Cause.squash(result.cause); + Alert.alert( + "Could not switch machine", + error instanceof Error + ? error.message + : "The folder for threads without a project could not be created.", + ); + return; + } + const project = await waitForProject({ environmentId, projectId: result.value.projectId }); + if (project === null) { + Alert.alert("Could not switch machine", "It has not reached this device yet. Try again."); + return; + } + flow.setProject(project); + navigation.goBack(); + } finally { + setMovingToEnvironmentId(null); + } + } return ( @@ -243,9 +278,17 @@ export function NewTaskEnvironmentPickerRouteScreen() { /> } isLast={index === flow.environments.length - 1} + disabled={movingToEnvironmentId !== null} onPress={() => { void Haptics.selectionAsync(); - flow.selectEnvironment(environment.environmentId); + if (flow.isScratchDraft) { + if (environment.environmentId !== flow.selectedEnvironmentId) { + void moveScratchDraft(environment.environmentId); + return; + } + } else { + flow.selectEnvironment(environment.environmentId); + } navigation.goBack(); }} selected={flow.selectedEnvironmentId === environment.environmentId} diff --git a/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx b/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx index 12f296a15e69..0772705645f2 100644 --- a/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx +++ b/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx @@ -1455,7 +1455,49 @@ export function NewTaskDraftScreen(props: { navigation.dispatch(StackActions.push(routeName)); }; - const hero = ( + const environmentControl = ( + ( + + )} + label={`on ${selectedEnvironmentLabel}`} + maxWidth={flow.isScratchDraft ? 170 : 260} + onPress={ + flow.environments.length > 1 ? () => openContextPicker("NewTaskEnvironment") : undefined + } + showChevron={flow.environments.length > 1} + static={flow.environments.length <= 1} + /> + ); + // A thread without a project has no project to name, so it asks plainly, + // like web, and puts the project picker beside the machine as a control. + const hero = flow.isScratchDraft ? ( + + + What should we work on? + + {/* Wraps onto two lines only when a long machine name leaves no room. */} + + + {environmentControl} + + + ) : ( @@ -1482,25 +1524,7 @@ export function NewTaskDraftScreen(props: { - ( - - )} - label={`on ${selectedEnvironmentLabel}`} - maxWidth={260} - onPress={ - flow.environments.length > 1 ? () => openContextPicker("NewTaskEnvironment") : undefined - } - showChevron={flow.environments.length > 1} - static={flow.environments.length <= 1} - /> + {environmentControl} ); const heroViewport = ( diff --git a/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx b/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx index 212846e26395..80a35eabd1c4 100644 --- a/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx +++ b/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx @@ -154,7 +154,16 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps + !scope.projects.every((project) => + isScratchProject(project, serverConfigs.get(project.environmentId)?.scratchWorkspaceRoot), + ), + ); + const visibleScopes = filterProjectScopes(listScopes, searchText); const resumedDestinationKeyRef = useRef(null); const reservedDestinationProject = incomingShare?.destination ? (projects.find( @@ -163,14 +172,13 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps canCreateProjectInEnvironment(environment.connectionState) && @@ -182,24 +190,7 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps - project.environmentId === scratchEnvironment?.environmentId && - isScratchProject(project, scratchWorkspaceRoot), - ); - const canStartScratch = scratchWorkspaceRoot !== null && reservedDestinationProject === null; - const scratchMachineLabel = - connectedEnvironments.length > 1 ? (scratchEnvironment?.environmentLabel ?? null) : null; - const startScratchLabel = scratchMachineLabel - ? `Start without a project on ${scratchMachineLabel}` - : "Start without a project"; - const scratchRowSubtitle = scratchMachineLabel - ? `On ${scratchMachineLabel}` - : "Start a task without a project"; + const canStartScratch = scratchEnvironment !== null && reservedDestinationProject === null; const scratchStartInFlightRef = useRef(false); async function selectProject(project: EnvironmentProject): Promise { @@ -321,7 +312,56 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps - {projectScopes.length === 0 ? ( + {canStartScratch && listScopes.length > 0 ? ( + Platform.OS === "android" ? ( + + void startScratch()} + leading={ + + } + /> + + ) : ( + + void startScratch()} + className="flex-row items-center gap-3 bg-card px-4 py-3.5" + > + + + + + No project + + Start a task without a project + + + + + + ) + ) : null} + {listScopes.length === 0 ? ( {canStartScratch ? ( void startScratch()} /> @@ -382,7 +422,7 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps void startScratch()} > - {startScratchLabel} + Start without a project ) : null} @@ -486,55 +526,6 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps )} - {canStartScratch && !scratchProjectExists && projectScopes.length > 0 ? ( - Platform.OS === "android" ? ( - - void startScratch()} - leading={ - - } - /> - - ) : ( - - void startScratch()} - className="flex-row items-center gap-3 bg-card px-4 py-3.5" - > - - - - - No project - - {scratchRowSubtitle} - - - - - - ) - ) : null} diff --git a/apps/mobile/src/features/threads/new-task-flow-provider.tsx b/apps/mobile/src/features/threads/new-task-flow-provider.tsx index a723c2fa29f6..ab598edd5d01 100644 --- a/apps/mobile/src/features/threads/new-task-flow-provider.tsx +++ b/apps/mobile/src/features/threads/new-task-flow-provider.tsx @@ -24,7 +24,12 @@ import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile"; import * as Arr from "effect/Array"; import { pipe } from "effect/Function"; -import { useEnvironmentServerConfig, useProjects, useThreadShells } from "../../state/entities"; +import { + useEnvironmentServerConfig, + useProjects, + useServerConfigs, + useThreadShells, +} from "../../state/entities"; import type { TurnCommandMetadata } from "../../lib/commandMetadata"; import type { DraftComposerAttachment } from "../../lib/composerImages"; import type { ModelOption, ProviderGroup } from "../../lib/modelOptions"; @@ -77,8 +82,10 @@ import { } from "../../state/use-thread-outbox"; import { setPendingConnectionError, + useRemoteConnectionStatus, useSavedRemoteConnections, } from "../../state/use-remote-environment-registry"; +import { canCreateProjectInEnvironment } from "@t3tools/client-runtime/operations/projects"; import { isScratchProject } from "@t3tools/client-runtime/state/projects"; import { EnvironmentProject } from "@t3tools/client-runtime/state/shell"; import { type VcsRef } from "@t3tools/client-runtime/state/vcs"; @@ -173,6 +180,8 @@ type NewTaskFlowContextValue = { readonly environmentLabel: string; }>; readonly selectedProject: EnvironmentProject | null; + /** True when the draft is a thread without a project (its machine's Scratch project). */ + readonly isScratchDraft: boolean; readonly modelOptions: ReadonlyArray; readonly selectedModel: ModelSelection | null; readonly selectedModelOption: ModelOption | null; @@ -339,6 +348,26 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { ? editingPendingProject : (projectsForEnvironment[0] ?? null)); + const selectedEnvironmentServerConfig = useEnvironmentServerConfig( + selectedProject?.environmentId ?? null, + ); + const isScratchDraft = + selectedProject !== null && + isScratchProject(selectedProject, selectedEnvironmentServerConfig?.scratchWorkspaceRoot); + const serverConfigs = useServerConfigs(); + const { connectedEnvironments } = useRemoteConnectionStatus(); + // A thread without a project can move to any connected machine that offers + // one; its Scratch project there is created on the switch if it is missing. + const scratchEnvironments = useMemo( + () => + connectedEnvironments.filter( + (environment) => + canCreateProjectInEnvironment(environment.connectionState) && + serverConfigs.get(environment.environmentId)?.scratchWorkspaceRoot !== undefined, + ), + [connectedEnvironments, serverConfigs], + ); + // Only offer machines that actually host the currently selected repository, so // switching computers moves the same repo across machines instead of jumping to // whatever unrelated project happens to be first on the other machine. Repository @@ -350,6 +379,12 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { const selectedWorkspaceBasename = selectedProject?.workspaceRoot.split("/").at(-1) || null; const selectedProjectTitle = selectedProject?.title ?? null; const environments = useMemo(() => { + if (isScratchDraft) { + return scratchEnvironments.map((environment) => ({ + environmentId: environment.environmentId, + environmentLabel: environment.environmentLabel, + })); + } const seen = new Set(); const result: Array<{ readonly environmentId: EnvironmentId; @@ -387,16 +422,15 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { } return result; }, [ + isScratchDraft, projects, savedConnectionsById, + scratchEnvironments, selectedRepositoryKey, selectedWorkspaceBasename, selectedProjectTitle, ]); - const selectedEnvironmentServerConfig = useEnvironmentServerConfig( - selectedProject?.environmentId ?? null, - ); // While a queued pending task is being edited its draft lives under a key // scoped to the queued message, so new-task drafts stay intact. const selectedProjectDraftKey = editingPendingTask @@ -457,10 +491,7 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { ); // A thread without a project runs in a plain folder, so worktree mode // would leave it unsendable: it is always local and offers no choice. - const canChooseWorkspace = !( - selectedProject !== null && - isScratchProject(selectedProject, selectedEnvironmentServerConfig?.scratchWorkspaceRoot) - ); + const canChooseWorkspace = !isScratchDraft; const defaultWorkspaceMode: WorkspaceMode = canChooseWorkspace ? projectSettings.settings.defaultThreadEnvMode : "local"; @@ -1192,6 +1223,7 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { expandedProvider, environments, selectedProject, + isScratchDraft, modelOptions, selectedModel, selectedModelOption, @@ -1241,6 +1273,7 @@ export function NewTaskFlowProvider(props: React.PropsWithChildren) { filteredBranches, finishEditingPendingTask, interactionMode, + isScratchDraft, planModeEnabled, loadBranches, loadMoreBranches, From 99e08526e5ec84f294940cba5929841518c52fec Mon Sep 17 00:00:00 2001 From: Kriday Dave Date: Fri, 2 Oct 2026 10:59:18 +0530 Subject: [PATCH 27/32] Remove unused isCloudDebugEnabled and isTerminalDebugEnabled (#14367) --- apps/mobile/src/features/cloud/cloudDebugLog.ts | 4 ---- apps/mobile/src/features/terminal/terminalDebugLog.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/apps/mobile/src/features/cloud/cloudDebugLog.ts b/apps/mobile/src/features/cloud/cloudDebugLog.ts index 7e57b39b7bb8..e2b904520bf2 100644 --- a/apps/mobile/src/features/cloud/cloudDebugLog.ts +++ b/apps/mobile/src/features/cloud/cloudDebugLog.ts @@ -5,10 +5,6 @@ const logger = createDebugLogger("cloud", { legacyGlobalFlag: "__T3_CLOUD_DEBUG__", }); -export function isCloudDebugEnabled(): boolean { - return logger.isEnabled(); -} - export function cloudDebugLog(event: string, data?: Record): void { logger.log(event, data); } diff --git a/apps/mobile/src/features/terminal/terminalDebugLog.ts b/apps/mobile/src/features/terminal/terminalDebugLog.ts index 31c8497915c3..2d7e5138cac1 100644 --- a/apps/mobile/src/features/terminal/terminalDebugLog.ts +++ b/apps/mobile/src/features/terminal/terminalDebugLog.ts @@ -12,10 +12,6 @@ const logger = createDebugLogger("terminal", { legacyGlobalFlag: "__T3_TERMINAL_DEBUG__", }); -export function isTerminalDebugEnabled(): boolean { - return logger.isEnabled(); -} - export function terminalDebugLog(message: string, data?: Record): void { logger.log(message, data); } From 54084ae1e6c32809db040e4fa571c80fdf2d8ae4 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 23:56:35 -0700 Subject: [PATCH 28/32] fix(mobile): update Expo 58 to restore widgets and Live Activities (#14734) --- apps/mobile/package.json | 67 +- ...o@58.0.3.patch => expo-audio@58.0.4.patch} | 0 ...ur@58.0.2.patch => expo-blur@58.0.3.patch} | 0 ....0.12.patch => expo-sharing@58.0.13.patch} | 18 +- ...8.0.9.patch => expo-widgets@58.0.11.patch} | 0 pnpm-lock.yaml | 697 +++++++++--------- pnpm-workspace.yaml | 93 +-- 7 files changed, 443 insertions(+), 432 deletions(-) rename patches/{expo-audio@58.0.3.patch => expo-audio@58.0.4.patch} (100%) rename patches/{expo-blur@58.0.2.patch => expo-blur@58.0.3.patch} (100%) rename patches/{expo-sharing@58.0.12.patch => expo-sharing@58.0.13.patch} (88%) rename patches/{expo-widgets@58.0.9.patch => expo-widgets@58.0.11.patch} (100%) diff --git a/apps/mobile/package.json b/apps/mobile/package.json index ae52098e59dd..d1bd5c810894 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -49,8 +49,8 @@ "@clerk/expo": "catalog:", "@effect/atom-react": "catalog:", "@expo-google-fonts/dm-sans": "^0.4.2", - "@expo/metro-runtime": "~58.0.9", - "@expo/ui": "~58.0.9", + "@expo/metro-runtime": "~58.0.10", + "@expo/ui": "~58.0.11", "@legendapp/list": "catalog:", "@material/material-color-utilities": "0.3.0", "@noble/curves": "catalog:", @@ -74,41 +74,41 @@ "clsx": "^2.1.1", "diff": "8.0.3", "effect": "catalog:", - "expo": "58.0.0", - "expo-asset": "~58.0.9", - "expo-audio": "58.0.3", - "expo-auth-session": "~58.0.6", - "expo-blur": "58.0.2", + "expo": "58.0.2", + "expo-asset": "~58.0.10", + "expo-audio": "58.0.4", + "expo-auth-session": "~58.0.7", + "expo-blur": "58.0.3", "expo-build-properties": "~58.0.9", - "expo-camera": "~58.0.5", - "expo-clipboard": "~58.0.2", + "expo-camera": "~58.0.7", + "expo-clipboard": "~58.0.3", "expo-constants": "~58.0.9", - "expo-crypto": "~58.0.3", - "expo-dev-client": "~58.0.9", - "expo-device": "~58.0.3", - "expo-document-picker": "~58.0.3", - "expo-file-system": "~58.0.4", - "expo-font": "~58.0.4", + "expo-crypto": "~58.0.4", + "expo-dev-client": "~58.0.10", + "expo-device": "~58.0.5", + "expo-document-picker": "~58.0.4", + "expo-file-system": "~58.0.5", + "expo-font": "~58.0.5", "expo-glass-effect": "58.0.3", - "expo-haptics": "~58.0.3", - "expo-image": "~58.0.8", - "expo-image-manipulator": "~58.0.10", - "expo-image-picker": "~58.0.9", - "expo-keep-awake": "~58.0.2", - "expo-linking": "~58.0.9", - "expo-network": "~58.0.2", - "expo-notifications": "~58.0.9", + "expo-haptics": "~58.0.4", + "expo-image": "~58.0.10", + "expo-image-manipulator": "~58.0.11", + "expo-image-picker": "~58.0.10", + "expo-keep-awake": "~58.0.3", + "expo-linking": "~58.0.10", + "expo-network": "~58.0.3", + "expo-notifications": "~58.0.11", "expo-paste-input": "^0.1.15", "expo-quick-actions": "^6.0.2", - "expo-secure-store": "~58.0.1", - "expo-sharing": "58.0.12", - "expo-splash-screen": "~58.0.2", - "expo-sqlite": "~58.0.7", + "expo-secure-store": "~58.0.2", + "expo-sharing": "58.0.13", + "expo-splash-screen": "~58.0.4", + "expo-sqlite": "~58.0.8", "expo-symbols": "~58.0.3", - "expo-updates": "~58.0.11", - "expo-video": "~58.0.5", - "expo-web-browser": "~58.0.3", - "expo-widgets": "58.0.9", + "expo-updates": "~58.0.13", + "expo-video": "~58.0.6", + "expo-web-browser": "~58.0.4", + "expo-widgets": "58.0.11", "react": "19.3.0", "react-dom": "19.3.0", "react-native": "0.88.0-rc.3", @@ -133,14 +133,15 @@ "@pierre/trees": "1.0.0-beta.4", "@types/react": "~19.3.0", "@types/react-dom": "~19.2.3", - "babel-preset-expo": "~58.0.6", + "babel-preset-expo": "~58.0.8", "tailwindcss": "^4.0.0", "typescript": "catalog:" }, "expo": { "install": { "exclude": [ - "react-native-keyboard-controller" + "react-native-keyboard-controller", + "typescript" ] }, "autolinking": { diff --git a/patches/expo-audio@58.0.3.patch b/patches/expo-audio@58.0.4.patch similarity index 100% rename from patches/expo-audio@58.0.3.patch rename to patches/expo-audio@58.0.4.patch diff --git a/patches/expo-blur@58.0.2.patch b/patches/expo-blur@58.0.3.patch similarity index 100% rename from patches/expo-blur@58.0.2.patch rename to patches/expo-blur@58.0.3.patch diff --git a/patches/expo-sharing@58.0.12.patch b/patches/expo-sharing@58.0.13.patch similarity index 88% rename from patches/expo-sharing@58.0.12.patch rename to patches/expo-sharing@58.0.13.patch index dd3bec580b17..536424d85f1f 100644 --- a/patches/expo-sharing@58.0.12.patch +++ b/patches/expo-sharing@58.0.13.patch @@ -1,5 +1,5 @@ diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt -index 0b87b53..65f1c57 100644 +index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644 --- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt +++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt @@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable { @@ -13,7 +13,7 @@ index 0b87b53..65f1c57 100644 @OptimizedRecord diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt -index 8dd50e8..481cdb4 100644 +index 3381c5fd207ebb4cd8e0301aac59d307939ff162..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644 --- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt +++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt @@ -3,6 +3,7 @@ package expo.modules.sharing @@ -24,7 +24,7 @@ index 8dd50e8..481cdb4 100644 internal class SimpleShareIntentDataParser { companion object { -@@ -17,21 +18,26 @@ internal class SimpleShareIntentDataParser { +@@ -17,25 +18,26 @@ internal class SimpleShareIntentDataParser { } private fun handleSendAction(context: Context, intent: Intent, type: String): List { @@ -40,7 +40,11 @@ index 8dd50e8..481cdb4 100644 + return listOf( SharePayload().apply { value = text -- shareType = if (isUrl) ShareType.Url else ShareType.Text +- shareType = if (isUrl) { +- ShareType.Url +- } else { +- ShareType.Text +- } - mimeType = "text/plain" + shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text + mimeType = type @@ -61,7 +65,7 @@ index 8dd50e8..481cdb4 100644 } private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List { -@@ -41,10 +47,25 @@ internal class SimpleShareIntentDataParser { +@@ -45,10 +47,25 @@ internal class SimpleShareIntentDataParser { private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload { val specificType = context.contentResolver.getType(uri) ?: defaultType @@ -89,7 +93,7 @@ index 8dd50e8..481cdb4 100644 } } diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts -index 74544e0..92bd2f5 100644 +index 74544e0728d5f845351693d8d90596abae42eaea..92bd2f53108ac717f1ef7292fe89aea05c676c5e 100644 --- a/build/Sharing.types.d.ts +++ b/build/Sharing.types.d.ts @@ -100,6 +100,11 @@ export type SharePayload = { @@ -105,7 +109,7 @@ index 74544e0..92bd2f5 100644 export type BaseResolvedSharePayload = SharePayload & { /** diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts -index 18af320..3a52b70 100644 +index 18af320420e7c01a8ffbd7fa5347320409f905d8..3a52b70a20efbc588ad5ca974c38c951e5757c97 100644 --- a/src/Sharing.types.ts +++ b/src/Sharing.types.ts @@ -108,6 +108,12 @@ export type SharePayload = { diff --git a/patches/expo-widgets@58.0.9.patch b/patches/expo-widgets@58.0.11.patch similarity index 100% rename from patches/expo-widgets@58.0.9.patch rename to patches/expo-widgets@58.0.11.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5da642b3b618..bdcd715c3a46 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,11 +102,11 @@ patchedDependencies: alchemy@2.0.0-beta.79: d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8 dbus-next@0.10.2: cfff57561b0ee59b5addb3b2e6c6f20906e967507a530ab67e8db8108e520ba4 effect@4.0.0-rc.115: 0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5 - expo-audio@58.0.3: c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742 - expo-blur@58.0.2: d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18 + expo-audio@58.0.4: c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742 + expo-blur@58.0.3: d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18 expo-glass-effect@58.0.3: f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57 - expo-sharing@58.0.12: 5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8 - expo-widgets@58.0.9: 94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b + expo-sharing@58.0.13: fe40d857765bcd6a77aac1fed275e5b8f9415c29b972decdce05fb96de5665e6 + expo-widgets@58.0.11: 94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b node-pty@1.2.0-beta.15: f2fe901c61cde17986240002d05c172d5d0272d83ffaab8d0ebeb922763be414 react-native-gesture-handler@3.2.1: d518a937e3cb2df5e7d67f1ab6b265c74a8639e4572d1b032b7b747e9b1c01a9 react-native-keyboard-controller@1.22.4: a438114039aed2e280a81d95c25723132ad071e4768fe492bd92aa628ad74597 @@ -243,7 +243,7 @@ importers: dependencies: '@clerk/expo': specifier: 4.6.8 - version: 4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(950bb7335d61b76ffb649f136fc0d4df) + version: 4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(9fda653cb5598772915b4a39a7aee91d) '@effect/atom-react': specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(react@19.3.0)(scheduler@0.27.0) @@ -251,11 +251,11 @@ importers: specifier: ^0.4.2 version: 0.4.2 '@expo/metro-runtime': - specifier: ~58.0.9 - version: 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.10 + version: 58.0.10(@expo/log-box@58.0.8)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/ui': - specifier: ~58.0.9 - version: 58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.11 + version: 58.0.11(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@legendapp/list': specifier: 'catalog:' version: 3.3.5(patch_hash=680cc6a5c5b4a4032e467e7b3fde22f89a84c0ee2e6eac6fda737d6277cc0806)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) @@ -303,7 +303,7 @@ importers: version: link:../../packages/contracts '@t3tools/mobile-markdown-text': specifier: file:./modules/t3-markdown-text - version: file:apps/mobile/modules/t3-markdown-text(5c46709ff7a3b3b481fcdaa30ae2beb2) + version: file:apps/mobile/modules/t3-markdown-text(afae94297d61d3a65abc2214f9b05422) '@t3tools/mobile-review-diff-native': specifier: file:./modules/t3-review-diff version: file:apps/mobile/modules/t3-review-diff @@ -326,110 +326,110 @@ importers: specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) expo: - specifier: 58.0.0 - version: 58.0.0(3abfa3879936d948a635873738556226) + specifier: 58.0.2 + version: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) expo-asset: - specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + specifier: ~58.0.10 + version: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-audio: - specifier: 58.0.3 - version: 58.0.3(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: 58.0.4 + version: 58.0.4(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-auth-session: - specifier: ~58.0.6 - version: 58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + specifier: ~58.0.7 + version: 58.0.7(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-blur: - specifier: 58.0.2 - version: 58.0.2(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: 58.0.3 + version: 58.0.3(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-build-properties: specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0) + version: 58.0.9(expo@58.0.2) expo-camera: - specifier: ~58.0.5 - version: 58.0.5(@types/emscripten@1.41.5)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.7 + version: 58.0.7(@types/emscripten@1.41.5)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-clipboard: - specifier: ~58.0.2 - version: 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-constants: specifier: 58.0.9 - version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + version: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) expo-crypto: - specifier: ~58.0.3 - version: 58.0.3(expo@58.0.0) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.2) expo-dev-client: - specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + specifier: ~58.0.10 + version: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-device: - specifier: ~58.0.3 - version: 58.0.3(expo@58.0.0) + specifier: ~58.0.5 + version: 58.0.5(expo@58.0.2) expo-document-picker: - specifier: ~58.0.3 - version: 58.0.3(expo@58.0.0) - expo-file-system: specifier: ~58.0.4 - version: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + version: 58.0.4(expo@58.0.2) + expo-file-system: + specifier: ~58.0.5 + version: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-font: - specifier: ~58.0.4 - version: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.5 + version: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-glass-effect: specifier: 58.0.3 - version: 58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + version: 58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-haptics: - specifier: ~58.0.3 - version: 58.0.3(expo@58.0.0) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.2) expo-image: - specifier: ~58.0.8 - version: 58.0.8(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo-image-manipulator: specifier: ~58.0.10 - version: 58.0.10(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + version: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-image-manipulator: + specifier: ~58.0.11 + version: 58.0.11(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-image-picker: - specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0) + specifier: ~58.0.10 + version: 58.0.10(expo@58.0.2) expo-keep-awake: - specifier: ~58.0.2 - version: 58.0.2(expo@58.0.0)(react@19.3.0) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.2)(react@19.3.0) expo-linking: - specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + specifier: ~58.0.10 + version: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-network: - specifier: ~58.0.2 - version: 58.0.2(expo@58.0.0)(react@19.3.0) + specifier: ~58.0.3 + version: 58.0.3(expo@58.0.2)(react@19.3.0) expo-notifications: - specifier: ~58.0.9 - version: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + specifier: ~58.0.11 + version: 58.0.11(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-paste-input: specifier: ^0.1.15 - version: 0.1.15(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + version: 0.1.15(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-quick-actions: specifier: ^6.0.2 - version: 6.0.2(expo@58.0.0)(typescript@7.0.2) + version: 6.0.2(expo@58.0.2)(typescript@7.0.2) expo-secure-store: - specifier: ~58.0.1 - version: 58.0.1(expo@58.0.0) + specifier: ~58.0.2 + version: 58.0.2(expo@58.0.2) expo-sharing: - specifier: 58.0.12 - version: 58.0.12(patch_hash=5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + specifier: 58.0.13 + version: 58.0.13(patch_hash=fe40d857765bcd6a77aac1fed275e5b8f9415c29b972decdce05fb96de5665e6)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) expo-splash-screen: - specifier: ~58.0.2 - version: 58.0.2(expo@58.0.0)(typescript@7.0.2) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.2)(typescript@7.0.2) expo-sqlite: - specifier: ~58.0.7 - version: 58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.8 + version: 58.0.8(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-symbols: specifier: ~58.0.3 - version: 58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + version: 58.0.3(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-updates: - specifier: ~58.0.11 - version: 58.0.11(expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.13 + version: 58.0.13(expo-dev-client@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-video: - specifier: ~58.0.5 - version: 58.0.5(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: ~58.0.6 + version: 58.0.6(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-web-browser: - specifier: ~58.0.3 - version: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + specifier: ~58.0.4 + version: 58.0.4(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-widgets: - specifier: 58.0.9 - version: 58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + specifier: 58.0.11 + version: 58.0.11(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react: specifier: 19.3.0 version: 19.3.0 @@ -483,7 +483,7 @@ importers: version: 3.6.0 uniwind: specifier: 1.11.0 - version: 1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3) + version: 1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3) devDependencies: '@effect/vitest': specifier: 4.0.0-rc.115 @@ -498,8 +498,8 @@ importers: specifier: ~19.2.3 version: 19.2.3(@types/react@19.3.0) babel-preset-expo: - specifier: ~58.0.6 - version: 58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2) + specifier: ~58.0.8 + version: 58.0.8(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.11)(expo@58.0.2)(react-refresh@0.14.2) tailwindcss: specifier: 4.3.3 version: 4.3.3 @@ -822,10 +822,10 @@ importers: version: link:../../packages/shared alchemy: specifier: 2.0.0-beta.79 - version: 2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + version: 2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(5f52a5feaac0b02f5e556737028925ac))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) drizzle-orm: specifier: 1.0.0-rc.5-ab785fc - version: 1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150) + version: 1.0.0-rc.5-ab785fc(5f52a5feaac0b02f5e556737028925ac) effect: specifier: 4.0.0-rc.115 version: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) @@ -2732,8 +2732,8 @@ packages: '@expo-google-fonts/material-symbols@0.4.38': resolution: {integrity: sha512-IJkBtN1o8u9BW5fvSii1MyHPQ7Q0HxbWcVBvOrOzgMLpVtZw7R2w94wBTVR7kZwv3w1JNTESMmLA5Sqn1+Z36A==} - '@expo/cli@58.0.9': - resolution: {integrity: sha512-qoCjBSbq8sFmhPHA0jgDvkRdGvVm9Wjti0U/zlrqYrH/lVolqT8++RvWebCLIGrT1WHQ9HWOmaL7szKqbhVgiA==} + '@expo/cli@58.1.1': + resolution: {integrity: sha512-6P3HlnwNOByOI2ntzhLcdWNDWkGrMmlIWOHXg5dslttr4HWV6E4rPsMmW4Pk29CXX5L2tvQNO8DR6SGGIAXo4w==} hasBin: true peerDependencies: expo: '*' @@ -2807,8 +2807,8 @@ packages: '@expo/log-box-utils@58.0.1': resolution: {integrity: sha512-BUDoo1BUsSNmGonRkVWBNI6moKsZxH/Tkt9a1pphOBJQMdr8/1HbhGEB84YOwaKMpMXMWAK6cwu3Ip8ax3J28g==} - '@expo/log-box@58.0.7': - resolution: {integrity: sha512-V6KY7IoeRZ7GqMRXQDrBF5w53w+a3PWWrNXnjzzkDC1uiaf2RN8qSACDPbJRUxJloL7X8EXnA7Q29i/YozxYSQ==} + '@expo/log-box@58.0.8': + resolution: {integrity: sha512-8kMrmfwry7bpG4913Kfovo2nOgJSfSxRkox6uv2JMCanxGYJRmFyad0j67dKviq3z5S/Tc5JxPpCgPRIU1YmJA==} peerDependencies: '@expo/dom-webview': 58.0.2 expo: '*' @@ -2829,10 +2829,10 @@ packages: '@expo/metro-file-map@58.0.3': resolution: {integrity: sha512-BAYHbRc89uX/mfxkK7oPe+YUXrPKE0rn3rq/e0E/PimUBeTfQjs1Y6Y7A4gLPuDTtSczyiZzFFJiTyA4MlNl5w==} - '@expo/metro-runtime@58.0.9': - resolution: {integrity: sha512-nWxcO3zFVIAMf9sw8n2meAy/pHlNQ1jbUe3aDYGun+slKx41sJ+xzd/Z2LFjuP2uzoyWE0v0zekEqzsA0fQ1AQ==} + '@expo/metro-runtime@58.0.10': + resolution: {integrity: sha512-EdcMLw3iWAYcNtW9Rv7VU+Nwrmn7digi4cAeTa2WX+FY0p3UeaoB+05kXnz7WgAqhIFge10ULgKHk7p14BcbXA==} peerDependencies: - '@expo/log-box': ^58.0.7 + '@expo/log-box': ^58.0.8 expo: '*' react: '*' react-dom: '*' @@ -2854,8 +2854,8 @@ packages: '@expo/plist@0.10.1': resolution: {integrity: sha512-nuNOqj+r/hGJbZ1Ax3jUpZaOB8UAMHUrISALJEUKaCieTflYj7224EqFWmMpriCGk9wXS1gH+9GGVnSj0tWzuQ==} - '@expo/prebuild-config@58.0.6': - resolution: {integrity: sha512-rnaPdJ+bSHRlJ2ElANH5P1QKtJSFSTxxR7FSh4qpwPfFJs6L3ozhOLP4R1z5oFCXq6MUQfYIDHb51rUfPAgDMg==} + '@expo/prebuild-config@58.0.7': + resolution: {integrity: sha512-HnePp+B1k2pc7ghU2ocVK8jXQiYUkGX8z9vqGWfhadIsUcjWkJ4jXehkrclC3A27LNzrq/KIrUneEvls6AwAAw==} '@expo/require-utils@55.0.5': resolution: {integrity: sha512-U4K/CQ2VpXuwfNGsN+daKmYOt15hCP8v/pXaYH6eut7kdYZo6SfJ1yr67BIcJ+1Gzzs+QzTxswAZChKpXmceyw==} @@ -2873,13 +2873,13 @@ packages: typescript: optional: true - '@expo/router-server@58.0.4': - resolution: {integrity: sha512-zoHpJzp7ltEY5w9eCINlkeCZg0BvtXexj0SIg/B9YGgFIiGYQDbtrQYy6eDc1lUICQn6ntzql3lrunegdConvw==} + '@expo/router-server@58.0.6': + resolution: {integrity: sha512-3MV28Py+VRwkszHrapiZCbAxyx0hxesLy11ibUay3gkNVFXgWc6ZLL4jX1WLyN/70Y8RUyNZ3dsEzIfSjlpnbQ==} peerDependencies: - '@expo/metro-runtime': ^58.0.9 + '@expo/metro-runtime': ^58.0.10 expo: '*' expo-constants: 58.0.9 - expo-font: ^58.0.4 + expo-font: ^58.0.5 expo-router: 58.0.10 expo-server: ^58.0.2 react: '*' @@ -2908,8 +2908,8 @@ packages: '@expo/sudo-prompt@9.3.2': resolution: {integrity: sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==} - '@expo/ui@58.0.9': - resolution: {integrity: sha512-uKwQb8zoDlbEw6jjHMA9OPzMVmo+sbnnKUhO/VNruaE3HF3swazCbrSRIomeznOVvyPP7EJsV5jXUrQgLAWzkg==} + '@expo/ui@58.0.11': + resolution: {integrity: sha512-rAT0xILSmV0rGjY+h6xGzcK5dfJFhPAsWULXiBfL8I6TwRZzfDy66u6YvPTxuUpEXH5cCeJDQ1p6v9tM792SMA==} peerDependencies: '@babel/core': '*' expo: '*' @@ -6196,12 +6196,12 @@ packages: babel-plugin-transform-flow-enums@0.0.2: resolution: {integrity: sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ==} - babel-preset-expo@58.0.6: - resolution: {integrity: sha512-e4PqE6comKx0CKZo2l1XlNoWE9mfabQvAHDk6CvqmDWMEh3vIJgBubZAbdBONsxaUqKON2SVnXKmmPD01iW1iA==} + babel-preset-expo@58.0.8: + resolution: {integrity: sha512-IWFxA+kKr6eX7+x1LMiBPYP10Cvo3d2QmmMpLPDP9Knv914VpuV0eK9Hka/cQSB9pPVzxHJn1bNee54qwwXgmg==} peerDependencies: '@babel/runtime': ^7.20.0 expo: '*' - expo-widgets: ^58.0.9 + expo-widgets: ^58.0.11 react-refresh: '>=0.14.0 <1.0.0' peerDependenciesMeta: '@babel/runtime': @@ -7184,34 +7184,34 @@ packages: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - expo-application@58.0.2: - resolution: {integrity: sha512-N1ivhudcdS6KmEm8S9W14L3WVgFnCUv85MU1YX+AYauJcs9IZWRoM7Wl1JU+PUUYvbVGLHoXNpu0aE3jVTdkFg==} + expo-application@58.0.3: + resolution: {integrity: sha512-SvRu9TcLIL1mqzJhRecHSF6N+s/CEExhPo0MiF5aikx9P4QmxCYYqdK4qO72wTYI5rqjmIwFhYx5dajF7FTzcw==} peerDependencies: expo: '*' - expo-asset@58.0.9: - resolution: {integrity: sha512-31fMfET8PyoCNGKmyjOY6fBTyTO7du80EjtrzZ/TsT+9zincWMUGwBWeby/fTXPHMEVgWQAiU2sKEteWEw8+Tg==} + expo-asset@58.0.10: + resolution: {integrity: sha512-u2ieyRfKwNoHhZhGoohzUbkTuHXWL2VgRP1gnh4CADoXler4HX95zm65r6eBtpIpNHAKxiVhdi828tAsFZtWsQ==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-audio@58.0.3: - resolution: {integrity: sha512-BwH1calLvev1jfU/ZF3GIpW76LOhevLXk+nur0FZRZyiZJYxYvvg6scO0+XAt0d7pk6/kiPIirPHFlWgb79fpw==} + expo-audio@58.0.4: + resolution: {integrity: sha512-Sdn4jhSh6HanIcs7MmyTSat/sVed4IEio4iC45QBTFEPMvL1b/LM9LfXuCu5eMqnSrdX/iDanCUYTisGRpMOEA==} peerDependencies: expo: '*' expo-asset: '*' react: '*' react-native: '*' - expo-auth-session@58.0.6: - resolution: {integrity: sha512-kTTQcZ2WgFxJlV2XtlBJxikADl8zPk1T2tTcC5c2ZOpjfAXHPDF/4pC9tfyYxNe0fOjCq9+t6aVL5X0uzZdVmg==} + expo-auth-session@58.0.7: + resolution: {integrity: sha512-4sJ3UiBhqFsVLUEWYDy2ZwZUDV7dmlC4AqR64k6hP3o2y4NVsPvDDOpKZIa1JZmox2qAIbtm89q/d/Bm4FUlNA==} peerDependencies: react: '*' react-native: '*' - expo-blur@58.0.2: - resolution: {integrity: sha512-2WKeR2FCSwTjTm+D0YLoLy/6rR583LYxlnhkB04zVkzWBiQKYCnOaUaOSsjQO2Nr/6ZpECmwXDhw4yzIuHZARQ==} + expo-blur@58.0.3: + resolution: {integrity: sha512-aqP279YTuioGLGq6wFPFKdSY4KRQYEri8MdbiCI99T8kPP1oPwTQP6iCKHQrxAebBNxoRTeN/4UXwpBB5uGkdw==} peerDependencies: expo: '*' react: '*' @@ -7222,8 +7222,8 @@ packages: peerDependencies: expo: '*' - expo-camera@58.0.5: - resolution: {integrity: sha512-UMc27NClJ5xnu2m/6Kz5zynOxJ7LluY0lgbu/TdxDZgGccjfM/myfLcO5r1FXaW84Llf3vTveG7SvwuRsNWIlQ==} + expo-camera@58.0.7: + resolution: {integrity: sha512-mHg/yWk2t9C1ORtjmbRthv7ZIWwnB+FDGVhqLx/sxWirXDoKb5tR7NZoYCCS8kfaAg7FZuPLSdvvvcjIe5iIsQ==} peerDependencies: expo: '*' react: '*' @@ -7233,8 +7233,8 @@ packages: react-native-web: optional: true - expo-clipboard@58.0.2: - resolution: {integrity: sha512-AiL1yU6iLX4sP8BZZyLzsSCo7XWysIBgVAck1vTqIkZm5PcVBeKiDgjXeJzG8nHBpti+ReeGhxbCaMQe7VbyMg==} + expo-clipboard@58.0.3: + resolution: {integrity: sha512-OglmYYTXecF9dti5sOYJS9lXAJpk6VDNqFvOLTm9fRdUjQj2D6UQV7q00jNZbRpf0ztMxlQSassUnzngn9wmvQ==} peerDependencies: expo: '*' react: '*' @@ -7246,18 +7246,18 @@ packages: expo: '*' react-native: '*' - expo-crypto@58.0.3: - resolution: {integrity: sha512-i6es/jfng4LDnmgVmHMCsFPA0ns3Iur9ypH+reRLVqH2Mgi9spYqZgpuhpX3gMyu0rKYylLz2YM8n5wxvhNp7w==} + expo-crypto@58.0.4: + resolution: {integrity: sha512-piLD8MCLuzkEmO/Obq4OsYoD2BBFU8IvEwgOfEhnkgzRp9fRrpg7sZIuZ3qtF0YIZI7S7yvsroPjG2Bj5Cx1vw==} peerDependencies: expo: '*' - expo-dev-client@58.0.9: - resolution: {integrity: sha512-JQPBDw0bZqZCqbOVxbphTaJXdlzuHcP7rXBxakWhotNy8nA5Ek4p6E8pIJu/OMWSLleoM0Dgtz05H/ShEHBItw==} + expo-dev-client@58.0.10: + resolution: {integrity: sha512-Eh69eX5W5/b2XGYPLFj6oVhGjOePayW4ne6rYTBr00NXp+b897xPS1qtDM7n7cbW2A+8f7L8HsxuRiOiSb8XAA==} peerDependencies: expo: '*' - expo-dev-launcher@58.0.9: - resolution: {integrity: sha512-wf7MDFbPOoTBD+ZWcFKyhxw+g1jghPL5yl9/r3PZmTiprpoMIZQXUBGpmnAHifJbA1Fhlhzm978tGU/Njr2t5Q==} + expo-dev-launcher@58.0.10: + resolution: {integrity: sha512-JXeg+yFn3kf5OcFkC9caFpmsPfDP+/lB+gNzBcIangmK8fLJY6hVQYs64vRuqTmeMHArX21il4AZ2yTfyd5F+A==} peerDependencies: expo: '*' react-native: '*' @@ -7267,33 +7267,33 @@ packages: peerDependencies: expo: '*' - expo-dev-menu@58.0.9: - resolution: {integrity: sha512-+VJMHf6XeGgVhQsJY+9CqKP2JTAv6n8Ki5NJt70BF0iqM5LzWa+/vwRna+HcTVYPA1KfHErSfL2WlLJT9LDNyQ==} + expo-dev-menu@58.0.10: + resolution: {integrity: sha512-Ic1DZYVkBFlJhCEXNVShgqWUno+axSQkES8qlCK88Y+yMSDFfV3owuJcBQYlY2SZ5Uy+FEySMXVl8C2VAUb3vw==} peerDependencies: expo: '*' react-native: '*' - expo-device@58.0.3: - resolution: {integrity: sha512-sK1xb02joE79KQ/c9c4oCaMhErjwUoL7IfInImRyxxmuEfKuzlNldBV61mahIrT3UyvYZBEwMM0Sx76Yqn7izg==} + expo-device@58.0.5: + resolution: {integrity: sha512-GNyaHPwoiI/z2SGR14R6d9J7hFSW2JabZieJtC3l6/LO2mJYVCbhEsQ7/1ljGBeTUnFFWHcFLccdaWEhOWtaQQ==} peerDependencies: expo: '*' - expo-document-picker@58.0.3: - resolution: {integrity: sha512-7oNPAhvzjGoF3Yhmkpw8GppXT05I0RC6qzskW4wbRgDFhuQRhE8eUvYU7T/Bq6NX1ERu5TUbTI0QS9zo3DO1SQ==} + expo-document-picker@58.0.4: + resolution: {integrity: sha512-rxs+9RrpI55/BEGNB/3sXjoBG6yZDLyn6Z7KzjbbBLdX8bE2cZT4IozQ3Q5wufaEEeaHQn48EgPiuMoTsAidpg==} peerDependencies: expo: '*' - expo-eas-client@58.0.1: - resolution: {integrity: sha512-FkomAg1uLen36v8U7jyzMKbdrMjKRSufB9qSCnhWnJynYkeWK4qAb9UyJBD/afkbTFQfq+ARImjM7IAi3V+2NA==} + expo-eas-client@58.0.2: + resolution: {integrity: sha512-mhRYnE35MzGxR1Xnl9FAg7/yHaocy4xoVzgsDmS9cbK+1wM6l74/I/73/E4Kr6wChdVZfeS6S+Tv4I1qYbGY2g==} - expo-file-system@58.0.4: - resolution: {integrity: sha512-w7Vuh1qA4fkZOSR4Zylvdr6bgOiH5p1hvfrnNlP+Xqb1x5h8Mu13yvQKUm4A1yc7BAeZ7CXu7//dw5hDEevFUg==} + expo-file-system@58.0.5: + resolution: {integrity: sha512-FFhwsD6mE54/56/qeCwecHjyBPaPFs7IbMKGF+pp8zUu9W5cVYq3VTgnKnwxrDgczPcs3gdrgL2DpBhK6jB7vQ==} peerDependencies: expo: '*' react-native: '*' - expo-font@58.0.4: - resolution: {integrity: sha512-AElYv+6hg7xgf8x7yL0zP8D2QrJuASU59iKC+yLd38SM6AvWFMlgBz0fkcgWtZFH7QI0Kz1WP+WsCQd06wYxBQ==} + expo-font@58.0.5: + resolution: {integrity: sha512-iN8btEnH+jSKzjF+1MVmnZHZZWtdsYevyBycMOAoOyuWV6RULOKirq+ql/VOzdanz2csLfXr40cc93k1Sft2pA==} peerDependencies: expo: '*' react: '*' @@ -7306,30 +7306,30 @@ packages: react: '*' react-native: '*' - expo-haptics@58.0.3: - resolution: {integrity: sha512-5chRroIhYhB2CG6Ce7sE82q4EATF9O4G7oyeUlDumcVAZzpNWWJkCZ7ucajyHOj2Wc/rArg2h7jYmwI3sgxnNA==} + expo-haptics@58.0.4: + resolution: {integrity: sha512-0LzHiAQggN6CMFuHrmA5e5WMP5/CKvbY6jEDWHCzIDyD1pzNwnkfoQVX0oTgEQZEgNSD1yejwmGRGGsI9sHdDQ==} peerDependencies: expo: '*' - expo-image-loader@58.0.2: - resolution: {integrity: sha512-anioFtqL5sl7556fw0vZOJBqICq0cpQAUUeQlFR40e9OJawCguWAs/FFpJYNX94DUYrp8YzlacThSWNyh0YPGw==} + expo-image-loader@58.0.3: + resolution: {integrity: sha512-zlHudxC8OObyqCHmvdxJqURI7886KJ0cUJyn7R/a8FOD9fP837xKDN+u4SIt7XsSSVPNXzMd4Y7mN0pmup8NGA==} peerDependencies: expo: '*' - expo-image-manipulator@58.0.10: - resolution: {integrity: sha512-JWapRwmOUq5RaePB1WKlEDgX/MewnRUeM6MKE0W7zEvbkyFYVn+4swUNOP3WDjDzu+To+878bqt7hcRcaqWzzA==} + expo-image-manipulator@58.0.11: + resolution: {integrity: sha512-aGgmOCERsPIJJT7agAhTUmVifSF5wFJ+m7lp7WcBzDe4yQ8ex49lDAQWUjl5ihCrW4my1i/rLlsp4tFuw1mSpA==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-image-picker@58.0.9: - resolution: {integrity: sha512-irYps0kkD+t17jHhBbQfm5Y9NbWXxULGyZPP/y90td3LE5zlFvFzNCj8Qnfif+ZFtg0QaL0T2fb/p5NLbfFA0w==} + expo-image-picker@58.0.10: + resolution: {integrity: sha512-yqQC9UYMWSUxk6U0jaS1vE1w+b9Ru0FJmQ3KjUf9Q9oVg5xBxmg8+Ts+usazMAuPoskNIXJ++VZ+uK6br9yUGQ==} peerDependencies: expo: '*' - expo-image@58.0.8: - resolution: {integrity: sha512-kRzMdDK+Cp0Iunz/psYnFDvt2MGTYA2qsZrey+nkH3XrtjTJVRD9hhdnHh35vLO3LXJsUNXfEvGnNV+ghnk0Hw==} + expo-image@58.0.10: + resolution: {integrity: sha512-Pka1lnGJR00RAFYJggLHfgspTIqGGhaJ+R5v1BpXLU50/xQRkjizMbCZfg1D2dNLhCddm8BdvvWlXeKkDRodug==} peerDependencies: expo: '*' react: '*' @@ -7342,14 +7342,14 @@ packages: expo-json-utils@58.0.1: resolution: {integrity: sha512-jNHNElOUPz2/vW3CbDKRn6tTF6eE9wwVbh/Isnqp5c/CdTcONzFVR3YHN3WQ05PnkmieyEqVfeOusOd1X9FDtQ==} - expo-keep-awake@58.0.2: - resolution: {integrity: sha512-UIddpQTJrYq/qsiuFHRJQwb1z1jojQ44XV2o6+bSuxLFKwO4KXp21to2GD3RkRFYLKdrEm98FLbzD9KpALkdKQ==} + expo-keep-awake@58.0.3: + resolution: {integrity: sha512-wLRF+XeVsD/Rt/ZyX+A0mk1brdf8vefWizNAPzqV5eOCgkj23LCRZdN8gUi5X8UwyR8UJ7Y7Dzdz4YDGB/4c9Q==} peerDependencies: expo: '*' react: '*' - expo-linking@58.0.9: - resolution: {integrity: sha512-EhA4cClb/rB8idwcrg0zQvgPxAiB0rnjy/zF9DLxmxxkTjV1Y1X3XphfeDxmoWNNf1gL9E47K/R6wsfJcni8aA==} + expo-linking@58.0.10: + resolution: {integrity: sha512-i4Pewp1woKPfevUAvlZFx7OT16W7VvYmN2Rv9SNUQQMoHn6Mn4Ug1lgMB63fejVuhjcNxy9nLsV2LEnU1mW3DA==} peerDependencies: expo: '*' react: '*' @@ -7360,12 +7360,12 @@ packages: peerDependencies: expo: '*' - expo-modules-autolinking@58.0.6: - resolution: {integrity: sha512-1O707KinH8UCUzi9JNeFqF87BJSh1fGgpwjdI/NzBhG2IoHAFQ1ngnpyqF6ikr/o01aGoBgjdCRRLfzEnop/IA==} + expo-modules-autolinking@58.0.7: + resolution: {integrity: sha512-P8JfFFgwa65qnTYfAuW8Ayept/MUUsEA/LcYaCY3CAC35oqWUX1/dsFowJCN+LyWv0EauMgx5eve/1Y8d9PWIA==} hasBin: true - expo-modules-core@58.0.9: - resolution: {integrity: sha512-0BD1t8aWXPGGA+222KzG4MA29iZVqBNJWCKoPKFwD9ab7x9wPkazLGifAp8m3VOYKLLMbzYD8uS9XTJdiplduA==} + expo-modules-core@58.0.11: + resolution: {integrity: sha512-uVBkEolRNB+9Tl6XlEHqOco+xw1tWkbFb7MFAOwPY9ExFYuM2TSmF9KvdwMCQNbmT0x5ENm6MIOeUcNG3U1cqg==} peerDependencies: react: '*' react-native: '*' @@ -7374,22 +7374,22 @@ packages: react-native-worklets: optional: true - expo-modules-jsi@58.0.5: - resolution: {integrity: sha512-5UMYPOEB1amqV7SCQKxJBvyZHycW4ZIeP3cwkv22pSE2nx3Hj6IymNz34TtIrCMcJAs6mO7MtG5OUsgwTp+iTQ==} + expo-modules-jsi@58.0.7: + resolution: {integrity: sha512-Rb7/NwhMw2DDSeQrYa5K91LLme5YNXIwodG5z2foFAVvAYTFVvF5o9pEYR4RdDjYtwxKXl5gE6FsRsE+/b4WbA==} peerDependencies: react-native: '*' expo-modules-macros@0.14.0: resolution: {integrity: sha512-R6ODnfK0Za+pSZZjv0SuOTV2YkxczeavvrsLv40gueH3U7QJ8H5OlD3kkFqyT68UzDLRJhwF52D884egtNH7Rw==} - expo-network@58.0.2: - resolution: {integrity: sha512-+Ek0nuLcZmW4f35L1lg4vo3lpotV0OUehFj8y5z0w/VEAw3WOeEzXh7Eo3TS6lIvsbyIJO7woWx8fYjMbGnhbA==} + expo-network@58.0.3: + resolution: {integrity: sha512-0WfFHUKt08Zk7ajaFzVDcZ4iNF3ywPVhGtxo7kDSiNQI4XO3MAqB6jYvpqf0D7+KQ28o/BIEkFdwkZl6AynIvw==} peerDependencies: expo: '*' react: '*' - expo-notifications@58.0.9: - resolution: {integrity: sha512-Ygi1bvJKMiv6wP0r9b3WzDkZy28EbIeagNvxyQqcy6FoyuUpAIXbH0IgnaAjK3czPWin78jC3GsDJYeZbHFPDg==} + expo-notifications@58.0.11: + resolution: {integrity: sha512-g7IYrZ+XvT+KBWvmPBCagK/9KHPLvdlky8g+h+lGBmKSlsgODnM/Vc+MrDjiBi+sQ99bI8mWm+wQqC8anfFlzA==} peerDependencies: expo: '*' react: '*' @@ -7407,8 +7407,8 @@ packages: peerDependencies: expo: '*' - expo-secure-store@58.0.1: - resolution: {integrity: sha512-jYKTkbXOlKrt3DiDw+f/EGc70UfyWNJgQiBEQ8ocyEpUehouyp9GcKza3gWixgLV8CWaCx4RtxiFQ5pFWaj0XQ==} + expo-secure-store@58.0.2: + resolution: {integrity: sha512-VupWWEuQF6IiQ06McSymtn7/tehs8ifThhFwAU4UK8poomZcaa2S0UVt/y7G2XozBdkI3xpiPSx+r0pS2zsuYQ==} peerDependencies: expo: '*' @@ -7416,20 +7416,20 @@ packages: resolution: {integrity: sha512-QOdIBRZ7hEhlKzDud99/4YPggg+rASCD901PuuDy/oHzSP+eQKs2B4PDwzwfYvtelDA45nOwJsyCKnBvwpuJZA==} engines: {node: ^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0} - expo-sharing@58.0.12: - resolution: {integrity: sha512-2uwxo2+9W6WzA87FnBiwCAWkrBAoNUrNY7mJHA5k3Q5i/je6tH2N65kl5pACpYEIOOShQkOAd4zz7DVc23JydA==} + expo-sharing@58.0.13: + resolution: {integrity: sha512-bsKsLYLyOd0A/Gy8pscv18ayqiI1enBP09s7Mepdy4IfQXjZBmOU1SK9SF+laL4Fg1qVkGZVLogAreI599Unag==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-splash-screen@58.0.2: - resolution: {integrity: sha512-rYs8/d8GGFKBfj1cecr8/87nfUcdSmqQq/enm8Wmv1IuC3l1dxnxFRWlnz2KORCYLUw42M2vNRqlSU9ETHt8GQ==} + expo-splash-screen@58.0.4: + resolution: {integrity: sha512-tG3DaTzOUwcIzY17+kMc0vICvcZCoaUD7jpmxmUziCfo4lGECv7uYd/u/cdwSCRHpuKqgLgMdbcocqU79YF/7g==} peerDependencies: expo: '*' - expo-sqlite@58.0.7: - resolution: {integrity: sha512-0ge3jryvlzEDyT7mXPEpTaqIIT65+n2noQfxBrWMdmSmuqL4L6eAYw/81C8UrXmDM97Y7vmmdR3abkMdN/a2mg==} + expo-sqlite@58.0.8: + resolution: {integrity: sha512-zDr/pMPqHKmuqMk85FxOEhAjvzKMzu7twvYDn9uf8J0qTOJJkzdU4clmlvc4duZalA2o58Y5NifD1yQEnHfuaA==} peerDependencies: expo: '*' react: '*' @@ -7451,8 +7451,8 @@ packages: peerDependencies: expo: '*' - expo-updates@58.0.11: - resolution: {integrity: sha512-7mijq0yyFhPExPO/IS/feFrmrbR6pZP3WOAYf07RkfW/3lacLBxWt5/rKG9QMe7ydbvjqMednhca1Rx48lB2mg==} + expo-updates@58.0.13: + resolution: {integrity: sha512-0WqK/tkFj966hD4ZpYtSbB63c1OYwWjtwE0KmEIo477f5x+fkgNGO7BOB28RgHatYqg+wtCLRKo0uJRVOujZsQ==} hasBin: true peerDependencies: expo: '*' @@ -7463,28 +7463,28 @@ packages: expo-dev-client: optional: true - expo-video@58.0.5: - resolution: {integrity: sha512-iJM0z/HR7Gocywq5Z4ou1CvTMaoGrXVNb1HzzENpqF+endoJcOGZFgV5uq+OGbiLtm7S/LSm/CCtcPwvVsdcCw==} + expo-video@58.0.6: + resolution: {integrity: sha512-47yyxMQYic2hu/SgnnezmtlyJlL9GOT4h47Uy6t3oR10GCqzfMj2ukwqYY7xvIwKnWz93ndGClUz0KtYEnfuhw==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo-web-browser@58.0.3: - resolution: {integrity: sha512-SEPI0pphJ6rCTtJ01OWNRDTxvEqCTl3TkVRC3erUC1CGUrz5UWCzK+ejUx4F1WEayfj4j9tQAw0JDc+dzDq26g==} + expo-web-browser@58.0.4: + resolution: {integrity: sha512-dt15sYiKpODdrkaTxr6ulaUl7RFPkCMVN7hxkMgDbEYGC58UZn4J7WkGBKyTDMy32r2jyFe/1+UpoyXzuoI1TA==} peerDependencies: expo: '*' react-native: '*' - expo-widgets@58.0.9: - resolution: {integrity: sha512-wGmI39qtJ6965rJA1bgAuKA2rEHfecoL939wxnBsSz3mvAAnSsjUNytP1rsVc0cBooPCssxqJST9EXGzee5Hfg==} + expo-widgets@58.0.11: + resolution: {integrity: sha512-vgXYPsjYYHNCU5iwOQk0JuEuXjP8dOj8XGk7Ztt+DI6vYcSYYgdBL3jIxi20wDUo/NqMO1tlOhtA36zcY2dchw==} peerDependencies: expo: '*' react: '*' react-native: '*' - expo@58.0.0: - resolution: {integrity: sha512-/KiC8tFY0hHl/mm49AFgNUFEQbnPthVh9o7EuDCSnTVpor8Cm/x1oqRyE97dxPT640lwuHO55xFO6OXopzjKXA==} + expo@58.0.2: + resolution: {integrity: sha512-hPtEOw4+a1QI6J2IiFx5QuVtAxphCL+GNRYn9CTnr8aOXDEAQNcPp5tb7G73y5BJSvkD50AMIn+sLAPARwi1Lw==} engines: {node: ^22.13.0 || ^24.3.0 || ^26.0.0 || >=27.0.0} hasBin: true peerDependencies: @@ -12061,24 +12061,24 @@ snapshots: electron-store: 8.2.0 react-dom: 19.3.0(react@19.3.0) - '@clerk/expo@4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(950bb7335d61b76ffb649f136fc0d4df)': + '@clerk/expo@4.6.8(patch_hash=b8b22ab733de5bea846ad9e88046c10582352fe9ad86f314f368b2a823f0f281)(9fda653cb5598772915b4a39a7aee91d)': dependencies: '@clerk/clerk-js': 6.32.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@clerk/react': 6.16.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@clerk/shared': 4.33.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@expo/config-plugins': 58.0.4(typescript@7.0.2) base-64: 1.0.0 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) react-native-url-polyfill: 4.0.0(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) tslib: 2.8.1 optionalDependencies: - expo-auth-session: 58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) - expo-crypto: 58.0.3(expo@58.0.0) - expo-secure-store: 58.0.1(expo@58.0.0) - expo-web-browser: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-auth-session: 58.0.7(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-crypto: 58.0.4(expo@58.0.2) + expo-secure-store: 58.0.2(expo@58.0.2) + expo-web-browser: 58.0.4(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - supports-color @@ -12762,7 +12762,7 @@ snapshots: '@expo-google-fonts/material-symbols@0.4.38': {} - '@expo/cli@58.0.9(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.9)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6)': + '@expo/cli@58.1.1(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.10)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6)': dependencies: 2g: 0.4.4(typescript@7.0.2) '@expo/code-signing-certificates': 0.0.6 @@ -12773,21 +12773,22 @@ snapshots: '@expo/image-utils': 0.12.2(typescript@7.0.2) '@expo/inline-modules': 0.2.1(typescript@7.0.2) '@expo/json-file': 11.2.1 - '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box': 58.0.8(@expo/dom-webview@58.0.2)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/log-box-utils': 58.0.1 '@expo/metro': 58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6) '@expo/metro-file-map': 58.0.3(typescript@7.0.2) '@expo/osascript': 2.8.1 '@expo/package-manager': 1.14.1 '@expo/plist': 0.10.1 - '@expo/prebuild-config': 58.0.6(typescript@7.0.2) + '@expo/prebuild-config': 58.0.7(typescript@7.0.2) '@expo/require-utils': 58.0.2(typescript@7.0.2) - '@expo/router-server': 58.0.4(@expo/metro-runtime@58.0.9)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@expo/router-server': 58.0.6(@expo/metro-runtime@58.0.10)(expo-constants@58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@expo/schema-utils': 58.0.1 '@expo/spawn-async': 1.8.0 '@expo/ws-tunnel': 2.0.0(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) '@expo/xcpretty': 4.4.4 + '@react-native/asset-utils': 0.88.0-rc.3 '@react-native/dev-middleware': 0.88.0-rc.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) '@react-native/js-polyfills': 0.88.0-rc.3 accepts: 1.3.8 @@ -12800,7 +12801,7 @@ snapshots: compression: 1.8.1 connect: 3.7.0 dnssd-advertise: 1.1.6 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) expo-server: 58.0.2 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -12889,17 +12890,17 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/devtools@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + '@expo/devtools@58.0.2(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: chalk: 4.1.2 optionalDependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - '@expo/dom-webview@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + '@expo/dom-webview@58.0.2(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) @@ -12975,18 +12976,18 @@ snapshots: '@expo/log-box-utils@58.0.1': {} - '@expo/log-box@58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + '@expo/log-box@58.0.8(@expo/dom-webview@58.0.2)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - '@expo/dom-webview': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/dom-webview': 58.0.2(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/log-box-utils': 58.0.1 anser: 1.4.10 react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) stacktrace-parser: 0.1.11 optionalDependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - '@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6)': + '@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6)': dependencies: 2g: 0.4.4(typescript@7.0.2) '@babel/code-frame': 7.29.7 @@ -13016,7 +13017,7 @@ snapshots: postcss: 8.5.28 resolve-from: 5.0.0 optionalDependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) transitivePeerDependencies: - bufferutil - supports-color @@ -13036,11 +13037,11 @@ snapshots: - supports-color - typescript - '@expo/metro-runtime@58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + '@expo/metro-runtime@58.0.10(@expo/log-box@58.0.8)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box': 58.0.8(@expo/dom-webview@58.0.2)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) anser: 1.4.10 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) pretty-format: 29.7.0 react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) @@ -13089,7 +13090,7 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 - '@expo/prebuild-config@58.0.6(typescript@7.0.2)': + '@expo/prebuild-config@58.0.7(typescript@7.0.2)': dependencies: '@expo/config': 58.0.1(typescript@7.0.2) '@expo/config-plugins': 58.0.4(typescript@7.0.2) @@ -13098,7 +13099,7 @@ snapshots: '@expo/json-file': 11.2.1 '@react-native/normalize-colors': 0.88.0-rc.3 debug: 4.4.3 - expo-modules-autolinking: 58.0.6(typescript@7.0.2) + expo-modules-autolinking: 58.0.7(typescript@7.0.2) resolve-from: 5.0.0 semver: 7.8.5 transitivePeerDependencies: @@ -13125,16 +13126,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@58.0.4(@expo/metro-runtime@58.0.9)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@expo/router-server@58.0.6(@expo/metro-runtime@58.0.10)(expo-constants@58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo-server@58.0.2)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: debug: 4.4.3 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) - expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-font: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) expo-server: 58.0.2 react: 19.3.0 optionalDependencies: - '@expo/metro-runtime': 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/metro-runtime': 58.0.10(@expo/log-box@58.0.8)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - supports-color @@ -13149,9 +13150,9 @@ snapshots: '@expo/sudo-prompt@9.3.2': {} - '@expo/ui@58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': + '@expo/ui@58.0.11(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)': dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 @@ -14661,15 +14662,15 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@t3tools/mobile-markdown-text@file:apps/mobile/modules/t3-markdown-text(5c46709ff7a3b3b481fcdaa30ae2beb2)': + '@t3tools/mobile-markdown-text@file:apps/mobile/modules/t3-markdown-text(afae94297d61d3a65abc2214f9b05422)': dependencies: '@t3tools/client-runtime': link:packages/client-runtime '@t3tools/shared': link:packages/shared - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) - expo-clipboard: 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo-haptics: 58.0.3(expo@58.0.0) - expo-symbols: 58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-asset: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-clipboard: 58.0.3(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-haptics: 58.0.4(expo@58.0.2) + expo-symbols: 58.0.3(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) react-native-nitro-markdown: 0.5.8(patch_hash=642b47830730acff3761fe29cf54271d18b493c0070c750097850b7ea032e00c)(react-native-nitro-modules@0.35.9(patch_hash=daf4a639ce3f951af630a3711e4082d58e3a11e5a79f45efb0b59925327ebde2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native-svg@15.15.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) @@ -15734,7 +15735,7 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - ? alchemy@2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + ? alchemy@2.0.0-beta.79(patch_hash=d1a03d902083946ee58121cc2787d88d1da561e9e30a5bcfcb8654692a489fb8)(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@effect/sql-pg@4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@types/node@24.12.4)(@types/react@19.3.0)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(bufferutil@4.1.0)(drizzle-kit@1.0.0-rc.5-ab785fc)(drizzle-orm@1.0.0-rc.5-ab785fc(5f52a5feaac0b02f5e556737028925ac))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(mongodb@6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9))(pg@8.23.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@7.0.2)(utf-8-validate@6.0.6)(ws@8.21.3(bufferutil@4.1.0)(utf-8-validate@6.0.6)) : dependencies: '@alchemy.run/cloudflare-runtime': 2.0.0-beta.79(@distilled.cloud/cloudflare@1.0.0-rc.12(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)))(@effect/platform-node@4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6))(@types/node@24.12.4)(@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0))(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(rolldown@1.2.5)(typescript@7.0.2) '@alchemy.run/floci': 2.0.0-beta.79(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) @@ -15774,7 +15775,7 @@ snapshots: '@effect/platform-node': 4.0.0-rc.115(bufferutil@4.1.0)(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5))(redis@6.2.1)(utf-8-validate@6.0.6) '@effect/sql-pg': 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) drizzle-kit: 1.0.0-rc.5-ab785fc - drizzle-orm: 1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150) + drizzle-orm: 1.0.0-rc.5-ab785fc(5f52a5feaac0b02f5e556737028925ac) mongodb: 6.21.0(@aws-sdk/credential-providers@3.1062.0)(socks@2.8.9) pg: 8.23.0 vite: '@voidzero-dev/vite-plus-core@1.0.0(@types/node@24.12.4)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.48.0)(typescript@7.0.2)(unrun@0.2.39)(yaml@2.9.0)' @@ -16060,7 +16061,7 @@ snapshots: transitivePeerDependencies: - '@babel/core' - babel-preset-expo@58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2): + babel-preset-expo@58.0.8(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.11)(expo@58.0.2)(react-refresh@0.14.2): dependencies: '@babel/generator': 7.29.7 '@babel/helper-module-imports': 7.29.7 @@ -16107,8 +16108,8 @@ snapshots: react-refresh: 0.14.2 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-widgets: 58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-widgets: 58.0.11(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -16723,7 +16724,7 @@ snapshots: get-tsconfig: 4.14.3 jiti: 2.7.0 - drizzle-orm@1.0.0-rc.5-ab785fc(7abae7c285f47308cc52e143cbe0c150): + drizzle-orm@1.0.0-rc.5-ab785fc(5f52a5feaac0b02f5e556737028925ac): optionalDependencies: '@cloudflare/workers-types': 4.20260604.1 '@effect/sql-d1': 4.0.0-rc.115(effect@4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5)) @@ -16734,7 +16735,7 @@ snapshots: '@libsql/client': 0.17.3(bufferutil@4.1.0)(utf-8-validate@6.0.6) bun-types: 1.3.14 effect: 4.0.0-rc.115(patch_hash=0dfc4bb8ebd80fb3e06b91ef61346f5259517ab0f2437644fe95ae531084b1f5) - expo-sqlite: 58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-sqlite: 58.0.8(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) pg: 8.23.0 valibot: 1.2.0(typescript@7.0.2) zod: 4.4.3 @@ -17003,35 +17004,35 @@ snapshots: expect-type@1.4.0: {} - expo-application@58.0.2(expo@58.0.0): + expo-application@58.0.3(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): + expo-asset@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: '@expo/image-utils': 0.12.2(typescript@7.0.2) - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-audio@58.0.3(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-audio@58.0.4(patch_hash=c20cb927d6848c53e7bf6ec14fe12f19daae9210165d2dbaf4e0f97ce31e8742)(expo-asset@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-asset: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-auth-session@58.0.6(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): + expo-auth-session@58.0.7(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - expo-application: 58.0.2(expo@58.0.0) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) - expo-crypto: 58.0.3(expo@58.0.0) - expo-linking: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) - expo-web-browser: 58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-application: 58.0.3(expo@58.0.2) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-crypto: 58.0.4(expo@58.0.2) + expo-linking: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-web-browser: 58.0.4(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) invariant: 2.2.4 react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) @@ -17040,143 +17041,143 @@ snapshots: - supports-color - typescript - expo-blur@58.0.2(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-blur@58.0.3(patch_hash=d0311b0c0b05bd94393bd9a84653cb42503d5f3c8a19eb2627c34ace08bedf18)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-build-properties@58.0.9(expo@58.0.0): + expo-build-properties@58.0.9(expo@58.0.2): dependencies: '@expo/schema-utils': 58.0.1 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) resolve-from: 5.0.0 semver: 7.8.5 - expo-camera@58.0.5(@types/emscripten@1.41.5)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-camera@58.0.7(@types/emscripten@1.41.5)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: barcode-detector: 3.2.0(@types/emscripten@1.41.5) - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - '@types/emscripten' - expo-clipboard@58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-clipboard@58.0.3(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2): + expo-constants@58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2): dependencies: '@expo/env': 2.5.1 '@expo/require-utils': 58.0.2(typescript@7.0.2) - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-crypto@58.0.3(expo@58.0.0): + expo-crypto@58.0.4(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-dev-client@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-dev-launcher: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) - expo-dev-menu: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) - expo-dev-menu-interface: 58.0.1(expo@58.0.0) - expo-manifests: 58.0.1(expo@58.0.0) - expo-updates-interface: 58.0.1(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-dev-launcher: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-dev-menu: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-dev-menu-interface: 58.0.1(expo@58.0.2) + expo-manifests: 58.0.1(expo@58.0.2) + expo-updates-interface: 58.0.1(expo@58.0.2) transitivePeerDependencies: - react-native - expo-dev-launcher@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-dev-launcher@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: '@expo/schema-utils': 58.0.1 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-dev-menu: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) - expo-manifests: 58.0.1(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-dev-menu: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-manifests: 58.0.1(expo@58.0.2) react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-dev-menu-interface@58.0.1(expo@58.0.0): + expo-dev-menu-interface@58.0.1(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-dev-menu@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-dev-menu@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-dev-menu-interface: 58.0.1(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-dev-menu-interface: 58.0.1(expo@58.0.2) react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-device@58.0.3(expo@58.0.0): + expo-device@58.0.5(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) ua-parser-js: 0.7.41 - expo-document-picker@58.0.3(expo@58.0.0): + expo-document-picker@58.0.4(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-eas-client@58.0.1: {} + expo-eas-client@58.0.2: {} - expo-file-system@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-file-system@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-glass-effect@58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-glass-effect@58.0.3(patch_hash=f750041c45ab838a3530451dc7b50d6640a79141037a1b0499c5e3412a860c57)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-haptics@58.0.3(expo@58.0.0): + expo-haptics@58.0.4(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-image-loader@58.0.2(expo@58.0.0): + expo-image-loader@58.0.3(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-image-manipulator@58.0.10(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-image-manipulator@58.0.11(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-image-loader: 58.0.2(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-image-loader: 58.0.3(expo@58.0.2) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-image-picker@58.0.9(expo@58.0.0): + expo-image-picker@58.0.10(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-image-loader: 58.0.2(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-image-loader: 58.0.3(expo@58.0.2) - expo-image@58.0.8(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-image@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 expo-json-utils@58.0.1: {} - expo-keep-awake@58.0.2(expo@58.0.0)(react@19.3.0): + expo-keep-awake@58.0.3(expo@58.0.2)(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 - expo-linking@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): + expo-linking@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) invariant: 2.2.4 react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) @@ -17184,12 +17185,12 @@ snapshots: - supports-color - typescript - expo-manifests@58.0.1(expo@58.0.0): + expo-manifests@58.0.1(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) expo-json-utils: 58.0.1 - expo-modules-autolinking@58.0.6(typescript@7.0.2): + expo-modules-autolinking@58.0.7(typescript@7.0.2): dependencies: '@expo/require-utils': 58.0.2(typescript@7.0.2) '@expo/spawn-async': 1.8.0 @@ -17199,9 +17200,9 @@ snapshots: - supports-color - typescript - expo-modules-core@58.0.9(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-modules-core@58.0.11(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo-modules-jsi: 58.0.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-modules-jsi: 58.0.7(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) expo-modules-macros: 0.14.0 invariant: 2.2.4 react: 19.3.0 @@ -17209,110 +17210,112 @@ snapshots: optionalDependencies: react-native-worklets: 0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo-modules-jsi@58.0.5(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-modules-jsi@58.0.7(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) expo-modules-macros@0.14.0: {} - expo-network@58.0.2(expo@58.0.0)(react@19.3.0): + expo-network@58.0.3(expo@58.0.2)(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 - expo-notifications@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): + expo-notifications@58.0.11(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: '@expo/image-utils': 0.12.2(typescript@7.0.2) abort-controller: 3.0.0 badgin: 1.2.3 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-application: 58.0.2(expo@58.0.0) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-application: 58.0.3(expo@58.0.2) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-paste-input@0.1.15(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-paste-input@0.1.15(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-quick-actions@6.0.2(expo@58.0.0)(typescript@7.0.2): + expo-quick-actions@6.0.2(expo@58.0.2)(typescript@7.0.2): dependencies: '@expo/image-utils': 0.8.14(typescript@7.0.2) - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) schema-utils: 4.3.3 sf-symbols-typescript: 2.2.0 transitivePeerDependencies: - supports-color - typescript - expo-secure-store@58.0.1(expo@58.0.0): + expo-secure-store@58.0.2(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) expo-server@58.0.2: {} - expo-sharing@58.0.12(patch_hash=5c85c709d951b5522b5bca897204b73ba7c17dec76e0dd155f41f8c2e833a7a8)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): + expo-sharing@58.0.13(patch_hash=fe40d857765bcd6a77aac1fed275e5b8f9415c29b972decdce05fb96de5665e6)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2): dependencies: '@expo/config-plugins': 58.0.4(typescript@7.0.2) '@expo/config-types': 58.0.2 '@expo/plist': 0.10.1 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: - supports-color - typescript - expo-splash-screen@58.0.2(expo@58.0.0)(typescript@7.0.2): + expo-splash-screen@58.0.4(expo@58.0.2)(typescript@7.0.2): dependencies: '@expo/config-plugins': 58.0.4(typescript@7.0.2) '@expo/image-utils': 0.12.2(typescript@7.0.2) - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) xml2js: 0.6.0 transitivePeerDependencies: - supports-color - typescript - expo-sqlite@58.0.7(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-sqlite@58.0.8(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: await-lock: 2.2.2 - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) expo-structured-headers@58.0.1: {} - expo-symbols@58.0.3(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-symbols@58.0.3(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@expo-google-fonts/material-symbols': 0.4.38 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-font: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) sf-symbols-typescript: 2.2.0 - expo-updates-interface@58.0.1(expo@58.0.0): + expo-updates-interface@58.0.1(expo@58.0.2): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) - expo-updates@58.0.11(expo-dev-client@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-updates@58.0.13(expo-dev-client@58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)))(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@expo/code-signing-certificates': 0.0.6 + '@expo/env': 2.5.1 '@expo/plist': 0.10.1 '@expo/spawn-async': 1.8.0 + '@react-native/asset-utils': 0.88.0-rc.3 arg: 4.1.3 chalk: 4.1.2 debug: 4.4.3 - expo: 58.0.0(3abfa3879936d948a635873738556226) - expo-eas-client: 58.0.1 - expo-manifests: 58.0.1(expo@58.0.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) + expo-eas-client: 58.0.2 + expo-manifests: 58.0.1(expo@58.0.2) expo-structured-headers: 58.0.1 - expo-updates-interface: 58.0.1(expo@58.0.0) + expo-updates-interface: 58.0.1(expo@58.0.2) getenv: 2.0.0 glob: 13.0.6 ignore: 5.3.2 @@ -17321,26 +17324,26 @@ snapshots: react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) resolve-from: 5.0.0 optionalDependencies: - expo-dev-client: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-dev-client: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) transitivePeerDependencies: - supports-color - expo-video@58.0.5(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-video@58.0.6(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-web-browser@58.0.3(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): + expo-web-browser@58.0.4(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)): dependencies: - expo: 58.0.0(3abfa3879936d948a635873738556226) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) - expo-widgets@58.0.9(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): + expo-widgets@58.0.11(patch_hash=94de7964c5a67ab40e6b79d9bdf4b7bfc50ae97b70722ee8e5a35105ca83386b)(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0): dependencies: '@expo/plist': 0.10.1 - '@expo/ui': 58.0.9(@babel/core@7.29.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo: 58.0.0(3abfa3879936d948a635873738556226) + '@expo/ui': 58.0.11(@babel/core@7.29.7)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo: 58.0.2(56fc8ddb8129740412739f0f0a6ee025) react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) transitivePeerDependencies: @@ -17348,36 +17351,36 @@ snapshots: - react-dom - react-native-worklets - expo@58.0.0(3abfa3879936d948a635873738556226): + expo@58.0.2(56fc8ddb8129740412739f0f0a6ee025): dependencies: '@babel/runtime': 7.29.7 - '@expo/cli': 58.0.9(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.9)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/cli': 58.1.1(@expo/dom-webview@58.0.2)(@expo/metro-runtime@58.0.10)(bufferutil@4.1.0)(expo-constants@58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2))(expo-font@58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2)(utf-8-validate@6.0.6) '@expo/config': 58.0.1(typescript@7.0.2) '@expo/config-plugins': 58.0.4(typescript@7.0.2) - '@expo/devtools': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/devtools': 58.0.2(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/fingerprint': 0.21.2 '@expo/local-build-cache-provider': 58.0.1(typescript@7.0.2) - '@expo/log-box': 58.0.7(@expo/dom-webview@58.0.2)(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/log-box': 58.0.8(@expo/dom-webview@58.0.2)(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) '@expo/log-box-utils': 58.0.1 '@expo/metro': 58.0.0-rc.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6) '@ungap/structured-clone': 1.3.1 - babel-preset-expo: 58.0.6(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.9)(expo@58.0.0)(react-refresh@0.14.2) - expo-asset: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) - expo-constants: 58.0.9(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) - expo-file-system: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) - expo-font: 58.0.4(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - expo-keep-awake: 58.0.2(expo@58.0.0)(react@19.3.0) - expo-modules-autolinking: 58.0.6(typescript@7.0.2) - expo-modules-core: 58.0.9(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + babel-preset-expo: 58.0.8(@babel/core@7.29.7)(@babel/runtime@7.29.7)(expo-widgets@58.0.11)(expo@58.0.2)(react-refresh@0.14.2) + expo-asset: 58.0.10(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(typescript@7.0.2) + expo-constants: 58.0.9(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(typescript@7.0.2) + expo-file-system: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6)) + expo-font: 58.0.5(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + expo-keep-awake: 58.0.3(expo@58.0.2)(react@19.3.0) + expo-modules-autolinking: 58.0.7(typescript@7.0.2) + expo-modules-core: 58.0.11(react-native-worklets@0.13.0(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) pretty-format: 29.7.0 react: 19.3.0 react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) react-refresh: 0.14.2 whatwg-url-minimum: 0.2.0 optionalDependencies: - '@expo/dom-webview': 58.0.2(expo@58.0.0)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) - '@expo/metro-runtime': 58.0.9(@expo/log-box@58.0.7)(expo@58.0.0)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/dom-webview': 58.0.2(expo@58.0.2)(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) + '@expo/metro-runtime': 58.0.10(@expo/log-box@58.0.8)(expo@58.0.2)(react-dom@19.3.0(react@19.3.0))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) react-dom: 19.3.0(react@19.3.0) react-native-webview: 14.0.1(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0) transitivePeerDependencies: @@ -20949,7 +20952,7 @@ snapshots: universalify@2.0.1: {} - uniwind@1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3): + uniwind@1.11.0(patch_hash=a91f3953483cfd434436de6358ff5b63c49974ef148fad91246c26ba95332625)(@expo/metro-config@58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6))(metro-cache@0.87.1)(metro-transform-worker@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(metro@0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react-native@0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6))(react@19.3.0)(tailwindcss@4.3.3): dependencies: '@tailwindcss/node': 4.3.3 '@tailwindcss/oxide': 4.3.3 @@ -20961,7 +20964,7 @@ snapshots: react-native: 0.88.0-rc.3(@babel/core@7.29.7)(@react-native/metro-config@0.88.0-rc.3(@babel/core@7.29.7)(bufferutil@4.1.0)(utf-8-validate@6.0.6))(@types/react@19.3.0)(bufferutil@4.1.0)(react@19.3.0)(utf-8-validate@6.0.6) tailwindcss: 4.3.3 optionalDependencies: - '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.0)(typescript@7.0.2)(utf-8-validate@6.0.6) + '@expo/metro-config': 58.0.6(patch_hash=90fa980e8b6480631fb2fbb04559834e3c612db40c550cd828f11be297d8d760)(bufferutil@4.1.0)(expo@58.0.2)(typescript@7.0.2)(utf-8-validate@6.0.6) metro-transform-worker: 0.87.1(bufferutil@4.1.0)(utf-8-validate@6.0.6) unpipe@1.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9a887cb06045..1fb8f63b8728 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -55,8 +55,8 @@ catalog: minimumReleaseAgeExclude: - expo-glass-effect@58.0.3 - - expo-blur@58.0.2 - - expo-audio@58.0.3 + - expo-blur@58.0.3 + - expo-audio@58.0.4 - "@clerk/backend@3.18.1" - "@clerk/clerk-js@6.32.1" - "@clerk/electron@0.0.44" @@ -78,39 +78,39 @@ minimumReleaseAgeExclude: - alchemy@2.0.0-beta.79 - effect@4.0.0-rc.115 - "@legendapp/list@3.3.5" - - "@expo/cli@58.0.9" + - "@expo/cli@58.1.1" - "@expo/env@2.5.1" - "@expo/fingerprint@0.21.2" - "@expo/metro-config@58.0.6" - expo-constants@58.0.9 - - expo-font@58.0.4 - - expo-updates@58.0.11 - - expo@58.0.0 - - expo-widgets@58.0.9 + - expo-font@58.0.5 + - expo-updates@58.0.13 + - expo@58.0.2 + - expo-widgets@58.0.11 - "@expo/config-plugins@58.0.4" - - "@expo/log-box@58.0.7" + - "@expo/log-box@58.0.8" - "@expo/metro-file-map@58.0.3" - - "@expo/metro-runtime@58.0.9" + - "@expo/metro-runtime@58.0.10" - "@expo/metro@58.0.0-rc.0" - - "@expo/prebuild-config@58.0.6" - - "@expo/router-server@58.0.4" - - "@expo/ui@58.0.9" - - babel-preset-expo@58.0.6 - - expo-asset@58.0.9 + - "@expo/prebuild-config@58.0.7" + - "@expo/router-server@58.0.6" + - "@expo/ui@58.0.11" + - babel-preset-expo@58.0.8 + - expo-asset@58.0.10 - expo-build-properties@58.0.9 - - expo-dev-client@58.0.9 - - expo-dev-launcher@58.0.9 - - expo-dev-menu@58.0.9 - - expo-image-manipulator@58.0.10 - - expo-image-picker@58.0.9 - - expo-image@58.0.8 - - expo-linking@58.0.9 - - expo-modules-autolinking@58.0.6 - - expo-modules-core@58.0.9 - - expo-modules-jsi@58.0.5 - - expo-notifications@58.0.9 - - expo-sharing@58.0.12 - - expo-sqlite@58.0.7 + - expo-dev-client@58.0.10 + - expo-dev-launcher@58.0.10 + - expo-dev-menu@58.0.10 + - expo-image-manipulator@58.0.11 + - expo-image-picker@58.0.10 + - expo-image@58.0.10 + - expo-linking@58.0.10 + - expo-modules-autolinking@58.0.7 + - expo-modules-core@58.0.11 + - expo-modules-jsi@58.0.7 + - expo-notifications@58.0.11 + - expo-sharing@58.0.13 + - expo-sqlite@58.0.8 - expo-symbols@58.0.3 - electron@44.4.2 - "@anthropic-ai/claude-agent-sdk@0.3.276" @@ -125,20 +125,20 @@ minimumReleaseAgeExclude: - "@shadcn/lint@0.1.5" - cn@0.3.2 - "@expo/dom-webview@58.0.2" - - "expo-auth-session@58.0.6" - - "expo-camera@58.0.5" - - "expo-clipboard@58.0.2" - - "expo-crypto@58.0.3" - - "expo-device@58.0.3" - - "expo-document-picker@58.0.3" - - "expo-file-system@58.0.4" - - "expo-haptics@58.0.3" - - "expo-keep-awake@58.0.2" - - "expo-network@58.0.2" - - "expo-secure-store@58.0.1" - - "expo-splash-screen@58.0.2" - - "expo-video@58.0.5" - - "expo-web-browser@58.0.3" + - "expo-auth-session@58.0.7" + - "expo-camera@58.0.7" + - "expo-clipboard@58.0.3" + - "expo-crypto@58.0.4" + - "expo-device@58.0.5" + - "expo-document-picker@58.0.4" + - "expo-file-system@58.0.5" + - "expo-haptics@58.0.4" + - "expo-keep-awake@58.0.3" + - "expo-network@58.0.3" + - "expo-secure-store@58.0.2" + - "expo-splash-screen@58.0.4" + - "expo-video@58.0.6" + - "expo-web-browser@58.0.4" - "react@19.3.0" - "react-dom@19.3.0" - "react-native@0.88.0-rc.3" @@ -147,6 +147,9 @@ minimumReleaseAgeExclude: - "react-native-reanimated@4.7.0" - "react-native-screens@4.28.0" - "@expo/config-types@58.0.2" + - expo-application@58.0.3 + - expo-eas-client@58.0.2 + - expo-image-loader@58.0.3 overrides: # Keep jsdom's optional peer consistent so Vite+ has one test-runner instance. @@ -231,13 +234,13 @@ packageExtensions: patchedDependencies: alchemy@2.0.0-beta.79: patches/alchemy@2.0.0-beta.79.patch expo-glass-effect@58.0.3: patches/expo-glass-effect@58.0.3.patch - expo-blur@58.0.2: patches/expo-blur@58.0.2.patch - expo-audio@58.0.3: patches/expo-audio@58.0.3.patch + expo-blur@58.0.3: patches/expo-blur@58.0.3.patch + expo-audio@58.0.4: patches/expo-audio@58.0.4.patch "@clerk/expo@4.6.8": patches/@clerk__expo@4.6.8.patch "@effect/vitest@4.0.0-rc.115": patches/@effect__vitest@4.0.0-rc.115.patch "@expo/metro-config@58.0.6": patches/@expo__metro-config@58.0.6.patch - expo-sharing@58.0.12: patches/expo-sharing@58.0.12.patch - expo-widgets@58.0.9: patches/expo-widgets@58.0.9.patch + expo-sharing@58.0.13: patches/expo-sharing@58.0.13.patch + expo-widgets@58.0.11: patches/expo-widgets@58.0.11.patch "@ff-labs/fff-node@0.9.4": patches/@ff-labs__fff-node@0.9.4.patch "@legendapp/list@3.3.5": patches/@legendapp__list@3.3.5.patch "@pierre/diffs@1.3.0-beta.10": patches/@pierre%2Fdiffs@1.3.0-beta.10.patch From ce96e4c3de1973c7e0088ef8806043841f902080 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Fri, 2 Oct 2026 09:43:40 -0700 Subject: [PATCH 29/32] fix(mobile): project picker cards match the settings card color (#14756) --- .../features/archive/ArchivedThreadsScreen.tsx | 4 ++-- .../cloud/ConnectOnboardingRouteScreen.tsx | 2 +- .../connection/ConnectionsNewRouteScreen.tsx | 4 ++-- .../src/features/projects/AddProjectScreen.tsx | 11 ++++++----- .../threads/NewTaskContextPickerScreens.tsx | 9 +++++---- .../src/features/threads/NewTaskRouteScreen.tsx | 16 +++++++++------- .../threads/ThreadSettingsRows.shared.tsx | 4 ++-- .../src/features/threads/ThreadSettingsSheet.tsx | 10 +++++----- .../src/features/usage/UsageLimitsPooled.tsx | 8 ++++---- .../src/features/usage/UsageRouteScreen.tsx | 4 ++-- 10 files changed, 38 insertions(+), 34 deletions(-) diff --git a/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx b/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx index 374d17ac4762..f0cebef2cee7 100644 --- a/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx +++ b/apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx @@ -190,7 +190,7 @@ function ArchivedThreadRow(props: { readonly thread: EnvironmentThreadShell; }) { const { width: windowWidth } = useWindowDimensions(); - const cardColor = useUniwindTheme()["--color-card"]; + const cardColor = useUniwindTheme()["--color-grouped-card"]; const timestamp = relativeTime(props.thread.archivedAt ?? props.thread.updatedAt); const subtitle = [props.environmentLabel, props.thread.branch].filter((part): part is string => Boolean(part), @@ -224,7 +224,7 @@ function ArchivedThreadRow(props: { > {() => ( ) : ( - + Sign in to your T3 account to set up T3 Connect. diff --git a/apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx b/apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx index bfcaf4013ab1..1cf2dfd6b69b 100644 --- a/apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx +++ b/apps/mobile/src/features/connection/ConnectionsNewRouteScreen.tsx @@ -226,7 +226,7 @@ export function ConnectionsNewRouteScreen({ /> ) : ( - + Camera permission is required to scan a QR code. @@ -242,7 +242,7 @@ export function ConnectionsNewRouteScreen({ ) ) : ( - + {props.children} @@ -197,6 +197,7 @@ function ListRow(props: { if (Platform.OS === "android") { return ( + Environment unavailable Start or reconnect an environment before adding a project. @@ -1333,7 +1334,7 @@ export function AddProjectDestinationScreen(props: { {error ? : null} {repositoryTitle ? ( - + {repositoryTitle} {remoteUrl} diff --git a/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx b/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx index 28e49cbdb5b9..930e6c1ec83e 100644 --- a/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx +++ b/apps/mobile/src/features/threads/NewTaskContextPickerScreens.tsx @@ -54,6 +54,7 @@ function SelectionRow(props: { if (Platform.OS === "android") { return ( void; }) { return ( - + {props.children} diff --git a/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx b/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx index 80a35eabd1c4..1ba1409d7976 100644 --- a/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx +++ b/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx @@ -314,8 +314,9 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps {canStartScratch && listScopes.length > 0 ? ( Platform.OS === "android" ? ( - + void startScratch()} @@ -330,12 +331,12 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps ) : ( - + void startScratch()} - className="flex-row items-center gap-3 bg-card px-4 py-3.5" + className="flex-row items-center gap-3 bg-grouped-card px-4 py-3.5" > {projectEmptyState.loading ? ( @@ -443,8 +444,8 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps {visibleScopes.map((scope, scopeIndex) => { @@ -456,6 +457,7 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps void selectProject(selectionTarget)} - className="flex-row items-center gap-3 bg-card px-4 py-3.5" + className="flex-row items-center gap-3 bg-grouped-card px-4 py-3.5" > diff --git a/apps/mobile/src/features/threads/ThreadSettingsSheet.tsx b/apps/mobile/src/features/threads/ThreadSettingsSheet.tsx index aedf415d02de..235d6c1e0f25 100644 --- a/apps/mobile/src/features/threads/ThreadSettingsSheet.tsx +++ b/apps/mobile/src/features/threads/ThreadSettingsSheet.tsx @@ -186,7 +186,7 @@ function DisclosureRow(props: { accessibilityRole="button" onPress={props.onPress} className={cn( - "min-h-11 flex-row items-center gap-2 bg-card px-4 py-2 active:bg-subtle android:min-h-14", + "min-h-11 flex-row items-center gap-2 bg-grouped-card px-4 py-2 active:bg-subtle android:min-h-14", !props.isLast && "border-b border-border-subtle", )} > @@ -216,7 +216,7 @@ function SwitchRow(props: { return ( @@ -700,7 +700,7 @@ function ThreadSettingsOptionsItem(props: { Options {session.displayedDescriptors.map((descriptor) => { @@ -754,7 +754,7 @@ function ThreadSettingsOptionsItem(props: { Catalog - + - + {submenuContent.rows.map((row, index) => ( + {label ?? pool.label} @@ -383,7 +383,7 @@ export function UsageLimitAccountScreen({ route }: AccountScreenProps) { ) : null} - + {window.label} {remainingPercent(window)}% left @@ -403,7 +403,7 @@ export function UsageLimitAccountScreen({ route }: AccountScreenProps) { ) : null} - + {account.environments.length ? "Signed in" : "Source"} @@ -418,7 +418,7 @@ export function UsageLimitAccountScreen({ route }: AccountScreenProps) { )} {account.redeem && account.limits.resetCredits ? ( - + Reset credits Cursor - + {CURSOR_KEYCHAIN_COPY} {environments.map((environment) => ( @@ -491,7 +491,7 @@ function ChartCard(props: { const hasActivity = props.daily.some((period) => period.totalTokens > 0); return ( - + {metric === "cost" ? "Raw token cost" : "Processed tokens"} From 4804036e04a025a35c46c02100d3c1706cd4fa47 Mon Sep 17 00:00:00 2001 From: "t3-code[bot]" <269035359+t3-code[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 16:55:22 +0000 Subject: [PATCH 30/32] chore(mobile): bump app version to 1.4.0 Co-authored-by: codex --- apps/mobile/app.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mobile/app.config.ts b/apps/mobile/app.config.ts index a1ab75b89fc2..8e6a2b7ad9ef 100644 --- a/apps/mobile/app.config.ts +++ b/apps/mobile/app.config.ts @@ -229,7 +229,7 @@ const config: ExpoConfig = { slug: "t3-code", platforms: ["ios", "android"], scheme: variant.scheme, - version: "1.3.1", + version: "1.4.0", runtimeVersion: { // Development manifests resolve on every launch, so avoid fingerprint's // expensive native-project calculation there. Preview and production stay From 6c8fed35dded9ff71c5b46807125457acbb76be6 Mon Sep 17 00:00:00 2001 From: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Date: Fri, 2 Oct 2026 13:33:23 -0400 Subject: [PATCH 31/32] fix(markdown): keep Windows paths intact in link and image destinations (#12615) Co-authored-by: Claude Opus 5.5 (1M context) --- .../src/SelectableMarkdownText.tsx | 10 ++--- .../src/nativeMarkdownText.ts | 30 +++++++++++++ .../mobile/src/lib/nativeMarkdownText.test.ts | 44 +++++++++++++++++++ apps/web/src/components/ChatMarkdown.tsx | 34 ++++++++++++++ .../ChatMarkdown.workspace-images.test.tsx | 39 ++++++++++++++++ 5 files changed, 152 insertions(+), 5 deletions(-) diff --git a/apps/mobile/modules/t3-markdown-text/src/SelectableMarkdownText.tsx b/apps/mobile/modules/t3-markdown-text/src/SelectableMarkdownText.tsx index 8e59256b12b8..6e118212690e 100644 --- a/apps/mobile/modules/t3-markdown-text/src/SelectableMarkdownText.tsx +++ b/apps/mobile/modules/t3-markdown-text/src/SelectableMarkdownText.tsx @@ -6,6 +6,7 @@ import { nativeMarkdownChunkSpacing, nativeMarkdownDocumentChunks, nativeMarkdownDocumentRuns, + nativeMarkdownWithAuthoredWindowsPaths, nativeMarkdownWithPreservedSoftBreaks, } from "./nativeMarkdownText"; import { MarkdownImageRendererContext, NativeMarkdownBlock } from "./NativeMarkdownBlock"; @@ -51,11 +52,10 @@ export function SelectableMarkdownText({ marginBottom = 0, }: SelectableMarkdownTextProps) { const chunks = useMemo(() => { - const parsedDocument = parseMarkdownWithOptions(markdown, { - gfm: true, - html: true, - math: false, - }); + const parsedDocument = nativeMarkdownWithAuthoredWindowsPaths( + parseMarkdownWithOptions(markdown, { gfm: true, html: true, math: false }), + markdown, + ); const document = preserveSoftBreaks ? nativeMarkdownWithPreservedSoftBreaks(parsedDocument) : parsedDocument; diff --git a/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts b/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts index 04682874db0c..a02a4a587153 100644 --- a/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts +++ b/apps/mobile/modules/t3-markdown-text/src/nativeMarkdownText.ts @@ -1,6 +1,7 @@ import type { MarkdownNode } from "react-native-nitro-markdown/headless"; import { collectComposerInlineTokens } from "@t3tools/shared/composerInlineTokens"; import { imageMimeType } from "@t3tools/shared/image"; +import { isWindowsAbsolutePath } from "@t3tools/shared/path"; import { videoMimeType } from "@t3tools/shared/video"; /** * Every accent shares a lightness so no kind reads heavier than another; only hue carries @@ -518,6 +519,35 @@ export function nativeMarkdownWithPreservedSoftBreaks(node: MarkdownNode): Markd }; } +const WINDOWS_DESTINATION_PATTERN = /\](?:\(|:)\s*\\])*)/g; +const MARKDOWN_ESCAPE_PATTERN = /\\([!-/:-@[-`{-~])/g; + +/** + * md4c reads the `\.` in `C:\me\.t3\shot.png` as an escape, even in a link destination. + * Every backslash in a Windows path is a separator, so link and image paths go back to + * the destination as written in `markdown`. A parsed path that more than one written + * destination could have produced stays as parsed. + */ +export function nativeMarkdownWithAuthoredWindowsPaths( + node: MarkdownNode, + markdown: string, +): MarkdownNode { + const authoredByParsed = new Map(); + for (const [, authored = ""] of markdown.matchAll(WINDOWS_DESTINATION_PATTERN)) { + if (!isWindowsAbsolutePath(authored)) continue; + const parsed = authored.replace(MARKDOWN_ESCAPE_PATTERN, "$1"); + const known = authoredByParsed.get(parsed); + authoredByParsed.set(parsed, known === undefined || known === authored ? authored : null); + } + if (authoredByParsed.size === 0) return node; + const restore = (current: MarkdownNode): MarkdownNode => { + const href = current.href && authoredByParsed.get(current.href); + const children = current.children?.map(restore); + return { ...current, ...(href ? { href } : {}), ...(children ? { children } : {}) }; + }; + return restore(node); +} + function appendBlockTerminator( runs: NativeMarkdownTextRun[], context: RunContext, diff --git a/apps/mobile/src/lib/nativeMarkdownText.test.ts b/apps/mobile/src/lib/nativeMarkdownText.test.ts index d934a306aa01..fca30deea89a 100644 --- a/apps/mobile/src/lib/nativeMarkdownText.test.ts +++ b/apps/mobile/src/lib/nativeMarkdownText.test.ts @@ -7,6 +7,7 @@ import { nativeMarkdownDocumentRuns, nativeMarkdownListItemBlocks, nativeMarkdownTextRuns, + nativeMarkdownWithAuthoredWindowsPaths, nativeMarkdownWithPreservedSoftBreaks, nativeMarkdownContextCopyRanges, contextChipPresentation, @@ -187,6 +188,49 @@ describe("nativeMarkdownTextRuns", () => { ]); }); + it("keeps Windows path backslashes the parser reads as escapes", () => { + const markdown = [ + String.raw`![shot](C:\Users\me\.t3\_build\shot.png "Shot")`, + String.raw`[settings](C:\Users\me\.claude\settings.json) and [site](https://example.com/a\.b)`, + "![ref][ref]", + String.raw`[ref]: \\wsl.localhost\Ubuntu\.t3\ref.png`, + ].join("\n\n"); + // md4c drops each backslash that precedes punctuation. + const node: MarkdownNode = { + type: "document", + children: [ + { type: "image", href: String.raw`C:\Users\me.t3_build\shot.png` }, + { type: "link", href: String.raw`C:\Users\me.claude\settings.json` }, + { type: "link", href: "https://example.com/a.b" }, + { type: "image", href: String.raw`\wsl.localhost\Ubuntu.t3\ref.png` }, + ], + }; + + expect( + nativeMarkdownWithAuthoredWindowsPaths(node, markdown).children?.map(({ href }) => href), + ).toEqual([ + String.raw`C:\Users\me\.t3\_build\shot.png`, + String.raw`C:\Users\me\.claude\settings.json`, + "https://example.com/a.b", + String.raw`\\wsl.localhost\Ubuntu\.t3\ref.png`, + ]); + }); + + it("leaves a Windows path as parsed when two written paths could have produced it", () => { + const markdown = [ + String.raw`\`![example](C:\Users\me\.t3\shot.png)\``, + String.raw`![real](C:\Users\me.t3\shot.png)`, + ].join("\n\n"); + const node: MarkdownNode = { + type: "document", + children: [{ type: "image", href: String.raw`C:\Users\me.t3\shot.png` }], + }; + + expect(nativeMarkdownWithAuthoredWindowsPaths(node, markdown).children?.[0]?.href).toBe( + String.raw`C:\Users\me.t3\shot.png`, + ); + }); + it("normalizes common inline HTML and entities", () => { const node: MarkdownNode = { type: "paragraph", diff --git a/apps/web/src/components/ChatMarkdown.tsx b/apps/web/src/components/ChatMarkdown.tsx index 4a1f616aed3b..ea02607cc115 100644 --- a/apps/web/src/components/ChatMarkdown.tsx +++ b/apps/web/src/components/ChatMarkdown.tsx @@ -89,6 +89,8 @@ import { parseAssistantCitationHref } from "@t3tools/shared/assistantCitations"; import { parseComposerContextHref } from "@t3tools/shared/composerContextReferences"; import { AssistantCitationChip } from "./chat/AssistantCitationChip"; import remarkGfm from "remark-gfm"; +import type { Processor } from "unified"; +import { isWindowsAbsolutePath } from "@t3tools/shared/path"; import { remarkGithubAlerts } from "../markdown-github-alerts"; import { artifactTemplateFromHastProperties, @@ -490,6 +492,7 @@ const CHAT_MARKDOWN_SANITIZE_SCHEMA = { const CHAT_MARKDOWN_REMARK_PLUGINS = [ remarkGfm, + remarkKeepWindowsPathDestinations, remarkGithubAlerts, remarkNormalizeListItemIndentation, remarkCodexDirectives, @@ -499,6 +502,7 @@ const CHAT_MARKDOWN_REMARK_PLUGINS = [ const CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS = [ remarkGfm, + remarkKeepWindowsPathDestinations, remarkGithubAlerts, remarkNormalizeListItemIndentation, remarkCodexDirectives, @@ -633,6 +637,36 @@ function remarkPreserveCodeMeta() { }; } +interface DestinationCompileContext { + readonly stack: ReadonlyArray<{ readonly type: string; url?: string }>; + resume(): string; + sliceSerialize(token: unknown): string; +} + +function keepWindowsPathDestination(this: DestinationCompileContext, token: unknown) { + const decoded = this.resume(); + const authored = this.sliceSerialize(token); + const node = this.stack.at(-1); + // Character references still need decoding, so those destinations keep the parsed URL. + if (node) + node.url = isWindowsAbsolutePath(authored) && !authored.includes("&") ? authored : decoded; +} + +/** + * CommonMark reads the `\.` in `C:\me\.t3\shot.png` as an escape, even in a link + * destination. Every backslash in a Windows path is a separator, so link, image, and + * definition destinations that are Windows paths keep the text as written. + */ +function remarkKeepWindowsPathDestinations(this: Processor) { + const data = this.data(); + (data.fromMarkdownExtensions ??= []).push({ + exit: { + resourceDestinationString: keepWindowsPathDestination, + definitionDestinationString: keepWindowsPathDestination, + }, + }); +} + /** * Preserve Windows drive links as allowed `file:` URLs before sanitization. * The same traversal tags inline code while it can still be distinguished diff --git a/apps/web/src/components/ChatMarkdown.workspace-images.test.tsx b/apps/web/src/components/ChatMarkdown.workspace-images.test.tsx index bab751c74816..a9c285e1f97b 100644 --- a/apps/web/src/components/ChatMarkdown.workspace-images.test.tsx +++ b/apps/web/src/components/ChatMarkdown.workspace-images.test.tsx @@ -185,6 +185,45 @@ describe("ChatMarkdown workspace images", () => { expect(html).toContain("https://signed.test/workspace-image.svg"); }); + it("keeps Windows path backslashes that CommonMark would read as escapes", () => { + const html = render( + [ + String.raw`![inline](C:\Users\shawn\.t3\_build\workspace-image.svg)`, + "![reference][shot]", + String.raw`[shot]: C:\Users\shawn\.t3\workspace-image.svg`, + String.raw`[settings](C:\Users\shawn\.claude\settings.json)`, + String.raw`![unc](\\wsl.localhost\Ubuntu\.t3\workspace-image.svg)`, + ].join("\n\n"), + ); + + expect(testState.resources).toEqual([ + { + _tag: "media-file", + threadId: threadRef.threadId, + path: String.raw`C:\Users\shawn\.t3\_build\workspace-image.svg`, + }, + { + _tag: "media-file", + threadId: threadRef.threadId, + path: "C:/Users/shawn/.t3/workspace-image.svg", + }, + { + _tag: "media-file", + threadId: threadRef.threadId, + path: String.raw`\\wsl.localhost\Ubuntu\.t3\workspace-image.svg`, + }, + ]); + expect(html).toContain('href="C:/Users/shawn/.claude/settings.json"'); + }); + + it("still decodes character references in Windows image paths", () => { + render("![amp](C:/Users/shawn/a&b.svg)"); + + expect(testState.resources).toEqual([ + { _tag: "media-file", threadId: threadRef.threadId, path: "C:/Users/shawn/a&b.svg" }, + ]); + }); + it("keeps a tall image placeholder and loaded image at the same proportional bounds", () => { const markdown = 'sized'; const loadedStyle = firstInlineStyle(render(markdown)); From af7de21e26967e6eb529298c9e8381dc117442c8 Mon Sep 17 00:00:00 2001 From: Julius Marminge <51714798+juliusmarminge@users.noreply.github.com> Date: Fri, 2 Oct 2026 10:53:52 -0700 Subject: [PATCH 32/32] test(web): import the drop helpers the Working shelf tests use The merge's Sidebar.logic.test.ts import list took V2's side, which had dropped resolveSidebarDropTarget and planSidebarThreadDrop, while main's Working shelf tests call both. Also formats isSidebarThreadWorking. Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/web/src/components/Sidebar.logic.test.ts | 3 ++- apps/web/src/components/Sidebar.logic.ts | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index 20e850f6e41d..33bdb2129bf9 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -20,7 +20,6 @@ import { getSidebarThreadIdsToPrewarm, hasUnseenCompletion, isContextMenuPointerDown, - isSidebarNestedLinkClick, isSidebarSubagentThread, isSidebarThreadWorking, isTrailingDoubleClick, @@ -44,6 +43,8 @@ import { shouldRecedeSidebarThread, sortLogicalProjectsForSidebar, sortInboxThreadsByReturn, + resolveSidebarDropTarget, + planSidebarThreadDrop, sortPinnedThreadsForSidebar, sortProjectsForSidebar, sortScopedProjectsForSidebar, diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index b26d868f930b..ad2c9a1fedc8 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -1010,9 +1010,7 @@ export function shouldShowSidebarV2Duration(status: SidebarThreadStatus): boolea the Working shelf: a running run, or one stopped with background tasks still open. Approvals, questions, plan prompts, and failures stay in the inbox. */ -export function isSidebarThreadWorking( - thread: ThreadStatusInput, -): boolean { +export function isSidebarThreadWorking(thread: ThreadStatusInput): boolean { const status = resolveSidebarThreadStatus(thread); if (status !== "working" && status !== "waiting") return false; // A plan prompt outranks lingering background work: the user has to act on it.

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 - + + Date: Thu, 1 Oct 2026 22:08:13 +0300 Subject: [PATCH 11/32] docs: update user count in AGENTS.md (#11413) --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 00425996ccc5..22e298879fc8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ You can think of T3 Code as an open source "bring-your-own-subscription" alterna ## What makes T3 Code special? -We have over 200,000 users who love T3 Code. It's important we maintain the things they love as we continue to iterate on the product. Here's a brief list of the things we can never compromise on. +We have over 400,000 users who love T3 Code. It's important we maintain the things they love as we continue to iterate on the product. Here's a brief list of the things we can never compromise on. ### 1. Open at the core From 5a574a77d1bef579b01d137b81888f68eabf7d4b Mon Sep 17 00:00:00 2001 From: "t3-code[bot]" <269035359+t3-code[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 16:09:52 -0300 Subject: [PATCH 12/32] test(web): remove duplicate sidebar ordering tests (#14558) Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> --- apps/web/src/components/Sidebar.logic.test.ts | 100 ------------------ apps/web/src/components/Sidebar.logic.ts | 2 +- 2 files changed, 1 insertion(+), 101 deletions(-) diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index fede3c183448..86cee77446f1 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -34,7 +34,6 @@ import { sortLogicalProjectsForSidebar, resolveSidebarDropTarget, pinOrderKeyBetween, - planPinnedReorder, planSidebarThreadDrop, sidebarMarkerId, sidebarListItemId, @@ -958,59 +957,6 @@ describe("reduceSidebarProjectScopeMenuState", () => { }); }); -describe("sortThreadsForSidebar", () => { - const sortable = (input: { id: string; createdAt: string }) => ({ - id: input.id, - createdAt: input.createdAt, - }); - - it("orders by creation time, newest first, ignoring activity", () => { - const sorted = sortThreadsForSidebar([ - sortable({ id: "oldest", createdAt: "2026-03-09T08:00:00.000Z" }), - sortable({ id: "newest", createdAt: "2026-03-09T12:00:00.000Z" }), - sortable({ id: "middle", createdAt: "2026-03-09T10:00:00.000Z" }), - ]); - - expect(sorted.map((thread) => thread.id)).toEqual(["newest", "middle", "oldest"]); - }); - - it("breaks creation-time ties by id so the order is stable", () => { - const sorted = sortThreadsForSidebar([ - sortable({ id: "b", createdAt: "2026-03-09T10:00:00.000Z" }), - sortable({ id: "a", createdAt: "2026-03-09T10:00:00.000Z" }), - ]); - - expect(sorted.map((thread) => thread.id)).toEqual(["a", "b"]); - }); - - it("surfaces an un-settled thread at the top via its re-entry stamp", () => { - const sorted = sortThreadsForSidebar([ - { - id: "old-unsettled", - createdAt: "2026-03-09T08:00:00.000Z", - unsettledAt: "2026-03-09T13:00:00.000Z", - }, - sortable({ id: "newest", createdAt: "2026-03-09T12:00:00.000Z" }), - sortable({ id: "middle", createdAt: "2026-03-09T10:00:00.000Z" }), - ]); - - expect(sorted.map((thread) => thread.id)).toEqual(["old-unsettled", "newest", "middle"]); - }); - - it("ignores a re-entry stamp older than the thread's creation", () => { - const sorted = sortThreadsForSidebar([ - { - id: "stale-stamp", - createdAt: "2026-03-09T10:00:00.000Z", - unsettledAt: "2026-03-09T09:00:00.000Z", - }, - sortable({ id: "newest", createdAt: "2026-03-09T12:00:00.000Z" }), - ]); - - expect(sorted.map((thread) => thread.id)).toEqual(["newest", "stale-stamp"]); - }); -}); - describe("pinOrderKeyBetween", () => { it("produces keys that sort between their bounds", () => { const middle = pinOrderKeyBetween(null, null)!; @@ -1062,52 +1008,6 @@ describe("pinOrderKeyBetween", () => { }); }); -describe("planPinnedReorder", () => { - it("writes only the moved thread when neighbors are keyed", () => { - const assignments = planPinnedReorder({ - orderedIds: ["a", "c", "b"], - keysById: new Map([ - ["a", "f"], - ["b", "m"], - ["c", "t"], - ]), - movedId: "c", - }); - expect(assignments).toHaveLength(1); - expect(assignments[0]!.id).toBe("c"); - expect(assignments[0]!.orderKey > "f" && assignments[0]!.orderKey < "m").toBe(true); - }); - - it("treats list edges as open bounds", () => { - const assignments = planPinnedReorder({ - orderedIds: ["b", "a"], - keysById: new Map([ - ["a", "m"], - ["b", null], - ]), - movedId: "b", - }); - expect(assignments).toHaveLength(1); - expect(assignments[0]!.orderKey < "m").toBe(true); - }); - - it("materializes keys for the whole section when a neighbor is keyless", () => { - const assignments = planPinnedReorder({ - orderedIds: ["b", "a", "c"], - keysById: new Map([ - ["a", null], - ["b", "m"], - ["c", null], - ]), - movedId: "b", - }); - expect(assignments.map((entry) => entry.id)).toEqual(["b", "a", "c"]); - const keys = assignments.map((entry) => entry.orderKey); - expect([...keys].sort()).toEqual(keys); - expect(new Set(keys).size).toBe(keys.length); - }); -}); - describe("resolveSidebarDropTarget", () => { const thread = (key: string, section: SidebarSection): SidebarListItem => ({ kind: "thread", diff --git a/apps/web/src/components/Sidebar.logic.ts b/apps/web/src/components/Sidebar.logic.ts index 2796b2f7f885..05664206105b 100644 --- a/apps/web/src/components/Sidebar.logic.ts +++ b/apps/web/src/components/Sidebar.logic.ts @@ -872,7 +872,7 @@ export { sortActiveThreadsByOrderKey as sortThreadsForSidebar } from "@t3tools/c // Pinned-reorder key math and the keyed sort live in client-runtime // (state/thread-sort) so web and mobile compute identical pinned orders. -export { pinOrderKeyBetween, planPinnedReorder } from "@t3tools/client-runtime/state/thread-sort"; +export { pinOrderKeyBetween } from "@t3tools/client-runtime/state/thread-sort"; export { sortPinnedThreadsByOrderKey as sortPinnedThreadsForSidebar } from "@t3tools/client-runtime/state/thread-sort"; const EMPTY_CONTENT_MATCH_KEYS: ReadonlySet = new Set(); From a97a4a9d189f145afe79c3a6f8533bbf9a6b40b1 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 12:26:09 -0700 Subject: [PATCH 13/32] Update marketing stats for GitHub stars and users --- apps/marketing/src/lib/site.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/marketing/src/lib/site.ts b/apps/marketing/src/lib/site.ts index dff2241f50c1..fbf564fd7e5f 100644 --- a/apps/marketing/src/lib/site.ts +++ b/apps/marketing/src/lib/site.ts @@ -7,6 +7,6 @@ export const ANDROID_PLAY_STORE_URL = "https://play.google.com/store/apps/details?id=com.t3tools.t3code"; export const MARKETING_STATS = { - githubStars: "22k+", - users: "300,000", + githubStars: "24k+", + users: "400,000", } as const; From 6ea01f8d24419019588f2be589681929d8e26b0c Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 1 Oct 2026 12:34:52 -0700 Subject: [PATCH 14/32] fix: cloned projects show their favicon instead of a monogram (#14635) Co-authored-by: Claude Opus 5.5 (1M context) --- apps/mobile/src/state/assets.ts | 2 + apps/mobile/src/state/projectClones.ts | 8 ++ apps/server/src/assets/AssetAccess.ts | 27 +++--- apps/server/src/server.test.ts | 81 ++++++++++++++++ apps/server/src/ws.ts | 7 ++ apps/web/src/state/assets.ts | 2 + apps/web/src/state/projectClones.ts | 2 +- .../client-runtime/src/state/assets.test.ts | 92 +++++++++++++++++++ packages/client-runtime/src/state/assets.ts | 22 ++++- 9 files changed, 230 insertions(+), 13 deletions(-) diff --git a/apps/mobile/src/state/assets.ts b/apps/mobile/src/state/assets.ts index b2fb759c5680..d6fefe2b8f86 100644 --- a/apps/mobile/src/state/assets.ts +++ b/apps/mobile/src/state/assets.ts @@ -18,6 +18,7 @@ import { environmentCatalog } from "../connection/catalog"; import { connectionAtomRuntime } from "../connection/runtime"; import { projectFaviconDatabaseCache } from "../lib/projectFaviconDatabaseCache"; import { type AssetUrlState, deriveAssetUrlState } from "./asset-url-state"; +import { environmentProjectCloneListAtom } from "./projectClones"; import { environmentSession, usePreparedConnection } from "./session"; import { useAtomQueryRunner } from "./use-atom-query-runner"; @@ -29,6 +30,7 @@ export const projectFaviconUrlAtom = createProjectFaviconUrlAtomFamily({ imageCache: projectFaviconDatabaseCache, createUrl: assetEnvironment.createUrl, preparedConnection: environmentSession.preparedConnectionValueAtom, + projectClones: environmentProjectCloneListAtom, }); const EMPTY_CONNECTION_STATE_ATOM = Atom.make(AsyncResult.initial(false)).pipe( diff --git a/apps/mobile/src/state/projectClones.ts b/apps/mobile/src/state/projectClones.ts index 9a86411e099d..018fbddfcf5a 100644 --- a/apps/mobile/src/state/projectClones.ts +++ b/apps/mobile/src/state/projectClones.ts @@ -36,6 +36,14 @@ const environmentProjectClonesAtom = Atom.family((environmentId: EnvironmentId) }).pipe(Atom.withLabel(`mobile-project-clones:${environmentId}`)), ); +/** The environment's tracked clones, empty until the stream's first list. */ +export const environmentProjectCloneListAtom = Atom.family((environmentId: EnvironmentId) => + Atom.make((get): ReadonlyArray => { + const clones = get(environmentProjectClonesAtom(environmentId)); + return clones === "pending" ? EMPTY_CLONES : clones; + }).pipe(Atom.withLabel(`mobile-project-clone-list:${environmentId}`)), +); + const projectCloneAtom = Atom.family((key: string) => { const ref = parseScopedProjectKey(key); return Atom.make((get): ProjectCloneState => { diff --git a/apps/server/src/assets/AssetAccess.ts b/apps/server/src/assets/AssetAccess.ts index 8dbd1c755966..25a2748cd9e5 100644 --- a/apps/server/src/assets/AssetAccess.ts +++ b/apps/server/src/assets/AssetAccess.ts @@ -419,6 +419,8 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i readonly resource: AssetResource; readonly workspaceRoot?: string; readonly projectFaviconPath?: string; + /** The project's clone has not landed, so its icon is reported missing without a lookup. */ + readonly projectCheckoutPending?: boolean; }) { const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; @@ -573,17 +575,20 @@ export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (i ), ); const faviconResolver = yield* ProjectFaviconResolver.ProjectFaviconResolver; - const faviconPath = yield* faviconResolver - .resolvePath(workspaceRoot, input.projectFaviconPath ?? undefined) - .pipe( - Effect.mapError( - (cause) => - new AssetProjectFaviconResolutionError({ - resource: input.resource, - cause, - }), - ), - ); + // A lookup in a half-cloned checkout would cache a miss that outlives the clone. + const faviconPath = input.projectCheckoutPending + ? null + : yield* faviconResolver + .resolvePath(workspaceRoot, input.projectFaviconPath ?? undefined) + .pipe( + Effect.mapError( + (cause) => + new AssetProjectFaviconResolutionError({ + resource: input.resource, + cause, + }), + ), + ); const isExternalOverride = faviconPath !== null && input.projectFaviconPath !== undefined && diff --git a/apps/server/src/server.test.ts b/apps/server/src/server.test.ts index fd505400c2e5..221941aa7833 100644 --- a/apps/server/src/server.test.ts +++ b/apps/server/src/server.test.ts @@ -8153,6 +8153,87 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }).pipe(Effect.provide(NodeHttpServer.layerTest)), ); + it.effect("finds a cloned project's icon once the clone lands", () => + Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem; + const path = yield* Path.Path; + const parentDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-ws-clone-favicon-" }); + const destinationPath = path.join(parentDir, "app"); + const projectId = ProjectId.make("project-clone-favicon"); + const cloneGate = yield* Deferred.make(); + const metaUpdateDispatched = yield* Deferred.make(); + + yield* buildAppUnderTest({ + layers: { + orchestrationEngine: { + dispatch: (command) => + (command.type === "project.meta.update" + ? Deferred.succeed(metaUpdateDispatched, undefined) + : Effect.void + ).pipe(Effect.as({ sequence: 1 })), + }, + projectionSnapshotQuery: { + getActiveProjectByWorkspaceRoot: (workspaceRoot) => + Effect.succeed( + workspaceRoot === destinationPath + ? Option.some({ + ...makeDefaultOrchestrationReadModel().projects[0]!, + id: projectId, + workspaceRoot, + }) + : Option.none(), + ), + }, + sourceControlRepositoryService: { + prepareClone: (input) => + Effect.succeed({ + destinationPath: input.destinationPath, + remoteUrl: input.remoteUrl ?? "", + cloneUrl: input.remoteUrl ?? "", + repository: null, + }), + cloneRepository: (input) => + Deferred.await(cloneGate).pipe( + Effect.andThen( + fs.writeFileString(path.join(input.destinationPath, "favicon.svg"), ""), + ), + Effect.orDie, + Effect.as({ + cwd: input.destinationPath, + remoteUrl: input.remoteUrl ?? "", + repository: null, + }), + ), + }, + }, + }); + + const wsUrl = yield* getWsServerUrl("/ws"); + yield* Effect.scoped( + withWsRpcClient(wsUrl, (client) => + Effect.gen(function* () { + yield* client[WS_METHODS.projectCloneStart]({ + projectId, + title: "app", + createdAt: "2026-01-01T00:00:00.000Z", + remoteUrl: "git@github.com:octocat/app.git", + destinationPath, + }); + const resource = { _tag: "project-favicon" as const, cwd: destinationPath }; + const duringClone = yield* client[WS_METHODS.assetsCreateUrl]({ resource }); + assert.isTrue(duringClone.relativeUrl.endsWith("/project-favicon-missing")); + + yield* Deferred.succeed(cloneGate, undefined); + yield* Deferred.await(metaUpdateDispatched); + // The lookup during the clone must not leave a cached miss behind. + const afterClone = yield* client[WS_METHODS.assetsCreateUrl]({ resource }); + assert.equal(afterClone.sourcePath, "favicon.svg"); + }), + ), + ); + }).pipe(Effect.provide(NodeHttpServer.layerTest)), + ); + it.effect("records thread analytics only after a client command succeeds", () => Effect.gen(function* () { const effects: string[] = []; diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts index f256dfaa4aa0..bcc19be00da5 100644 --- a/apps/server/src/ws.ts +++ b/apps/server/src/ws.ts @@ -3508,11 +3508,18 @@ const makeWsRpcLayer = ( resource: input.resource, }); } + // A cloned project exists before its files do. Clients ask again + // when the clone lands (see createProjectFaviconUrlAtomFamily). + const clone = yield* projectCloneTracker.get(project.value.id); return yield* issueAssetUrl({ resource: input.resource, ...(project.value.faviconPath ? { projectFaviconPath: project.value.faviconPath } : {}), + projectCheckoutPending: + clone !== null && + clone.phase !== "done" && + clone.destinationPath === project.value.workspaceRoot, }); } const thread = yield* projectionSnapshotQuery diff --git a/apps/web/src/state/assets.ts b/apps/web/src/state/assets.ts index 672e2d88672d..fe2acba3f9ac 100644 --- a/apps/web/src/state/assets.ts +++ b/apps/web/src/state/assets.ts @@ -8,6 +8,7 @@ import { connectionAtomRuntime } from "../connection/runtime"; import { projectFaviconCache } from "../assets/projectFaviconCache"; import { isElectron } from "../env"; import { primaryEnvironmentIdAtom } from "./primaryEnvironment"; +import { environmentProjectClonesAtom } from "./projectClones"; import { environmentSession } from "./session"; const localMediaEnvironment = Atom.make((get) => { @@ -31,4 +32,5 @@ export const projectFaviconUrlAtom = createProjectFaviconUrlAtomFamily({ imageCache: projectFaviconCache, createUrl: assetEnvironment.createUrl, preparedConnection: environmentSession.preparedConnectionValueAtom, + projectClones: environmentProjectClonesAtom, }); diff --git a/apps/web/src/state/projectClones.ts b/apps/web/src/state/projectClones.ts index b5645167c1cc..7cc95c8ba00e 100644 --- a/apps/web/src/state/projectClones.ts +++ b/apps/web/src/state/projectClones.ts @@ -16,7 +16,7 @@ const EMPTY_CLONE_ATOM = Atom.make(null).pipe( * Latest clone list an environment has streamed; empty until the subscription * delivers, and never subscribed on servers that predate clone tracking. */ -const environmentProjectClonesAtom = Atom.family((environmentId: EnvironmentId) => +export const environmentProjectClonesAtom = Atom.family((environmentId: EnvironmentId) => Atom.make((get): ReadonlyArray => { const supported = get(environmentServerConfigsAtom).get(environmentId)?.environment.capabilities diff --git a/packages/client-runtime/src/state/assets.test.ts b/packages/client-runtime/src/state/assets.test.ts index bd266f261675..e3190079afc1 100644 --- a/packages/client-runtime/src/state/assets.test.ts +++ b/packages/client-runtime/src/state/assets.test.ts @@ -6,6 +6,8 @@ import { AssetWorkspaceContextNotFoundError, EnvironmentAuthorizationError, EnvironmentId, + type ProjectCloneSnapshot, + ProjectId, ThreadId, WS_METHODS, } from "@t3tools/contracts"; @@ -409,4 +411,94 @@ describe("project favicon URL cache", () => { registry.dispose(); } }); + + const cloning: ProjectCloneSnapshot = { + projectId: ProjectId.make("project-cloning"), + remoteUrl: "git@github.com:octocat/app.git", + destinationPath: "/workspace", + repository: null, + phase: "running", + stage: "receiving", + percent: 10, + detail: null, + error: null, + startedAt: "2026-01-01T00:00:00.000Z", + endedAt: null, + sequence: 1, + }; + + function mountClonedProjectFavicon(initialClones: ReadonlyArray) { + const registry = AtomRegistry.make(); + // Stands in for the server, which reports the icon missing until the clone lands. + const server = { lookups: 0, landed: false }; + const result = Atom.make(() => { + server.lookups += 1; + return AsyncResult.success({ + expiresAt: 4_000_000_000_000, + relativeUrl: server.landed + ? "/api/assets/token-b/v1-icon.svg" + : "/api/assets/token-a/project-favicon-missing", + }); + }); + const clones = Atom.make(initialClones); + const connection = Atom.make(Option.some({ httpBaseUrl: "https://remote.test" })); + const favicon = createProjectFaviconUrlAtomFamily({ + createUrl: () => result, + preparedConnection: () => connection, + projectClones: () => clones, + })({ environmentId: EnvironmentId.make("remote"), cwd: "/workspace" }); + const unmount = registry.mount(favicon); + return { + registry, + server, + clones, + favicon, + dispose: () => { + unmount(); + registry.dispose(); + }, + }; + } + + it("asks for a cloned project's icon again once its clone lands", () => { + const { registry, server, clones, favicon, dispose } = mountClonedProjectFavicon([cloning]); + try { + expect(registry.get(favicon)).toBe( + "https://remote.test/api/assets/token-a/project-favicon-missing", + ); + // Progress, and another folder's clone landing, do not ask again. + registry.set(clones, [ + { ...cloning, percent: 80, sequence: 2 }, + { + ...cloning, + projectId: ProjectId.make("project-other"), + destinationPath: "/other", + phase: "done", + sequence: 3, + }, + ]); + expect(server.lookups).toBe(1); + + server.landed = true; + registry.set(clones, [{ ...cloning, phase: "done", sequence: 4 }]); + expect(registry.get(favicon)).toBe("https://remote.test/api/assets/token-b/v1-icon.svg"); + expect(server.lookups).toBe(2); + } finally { + dispose(); + } + }); + + it("asks again when the first clone list it sees already says done", () => { + const { registry, server, clones, favicon, dispose } = mountClonedProjectFavicon([]); + try { + expect(registry.get(favicon)).toBe( + "https://remote.test/api/assets/token-a/project-favicon-missing", + ); + server.landed = true; + registry.set(clones, [{ ...cloning, phase: "done", sequence: 2 }]); + expect(registry.get(favicon)).toBe("https://remote.test/api/assets/token-b/v1-icon.svg"); + } finally { + dispose(); + } + }); }); diff --git a/packages/client-runtime/src/state/assets.ts b/packages/client-runtime/src/state/assets.ts index 0729d1bfeaa5..670246610248 100644 --- a/packages/client-runtime/src/state/assets.ts +++ b/packages/client-runtime/src/state/assets.ts @@ -4,6 +4,7 @@ import { type AssetImageDimensions, AssetResource, EnvironmentId, + type ProjectCloneSnapshot, WS_METHODS, } from "@t3tools/contracts"; import { mediaMimeTypeFromExtension } from "@t3tools/shared/filePreview"; @@ -181,14 +182,33 @@ export function createProjectFaviconUrlAtomFamily(input: { readonly preparedConnection: ( environmentId: EnvironmentId, ) => Atom.Atom>; + /** The environment's tracked clones, empty when it reports none. */ + readonly projectClones?: ( + environmentId: EnvironmentId, + ) => Atom.Atom>; }) { const decodeKey = Schema.decodeUnknownSync( Schema.Tuple([EnvironmentId, Schema.String, Schema.NullOr(Schema.String)]), ); + const projectClones = input.projectClones; const family = Atom.family((key: string) => { const [environmentId, cwd, path] = decodeKey(JSON.parse(key)); const resource = { _tag: "project-favicon" as const, cwd, ...(path ? { path } : {}) }; - const request = input.createUrl({ environmentId, input: { resource } }); + const query = input.createUrl({ environmentId, input: { resource } }); + // A cloned project exists before its files do, and the server reports its + // icon missing until the clone lands. Ask again whenever the clone's phase + // changes: the first list a client sees may already say done. + const request = projectClones + ? query.pipe( + Atom.makeRefreshOnSignal( + Atom.make( + (get) => + get(projectClones(environmentId)).find((clone) => clone.destinationPath === cwd) + ?.phase ?? null, + ), + ), + ) + : query; const resolvedUrl = Atom.make((get): string | null => { const result = get(request); const connection = get(input.preparedConnection(environmentId)); From 094fb230e90ffb0af303a318ca716fecefd66c80 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 13:06:35 -0700 Subject: [PATCH 15/32] docs: server features are services, and handlers stay thin (#14613) Co-authored-by: Claude Opus 5.5 (1M context) --- .../effect-service-conventions.md | 9 +- AGENTS.md | 4 +- docs/internals/effect-services.md | 84 +++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 docs/internals/effect-services.md diff --git a/.macroscope/check-run-agents/effect-service-conventions.md b/.macroscope/check-run-agents/effect-service-conventions.md index 66ee81306a5a..52fd09fd1b33 100644 --- a/.macroscope/check-run-agents/effect-service-conventions.md +++ b/.macroscope/check-run-agents/effect-service-conventions.md @@ -22,7 +22,7 @@ showToolCalls: true # Effect service review -Review changed TypeScript for the conventions below. They apply when a pull request creates, moves, refactors, or consumes an Effect service. Review only the lines the PR changed; older code in the same file that predates these conventions is not a finding. Do not demand repository-wide cleanup. +Review changed TypeScript for the conventions below. They apply when a pull request creates, moves, refactors, or consumes an Effect service, or adds server behavior. Authors read the same rules in `docs/internals/effect-services.md`; keep the two in step. Review only the lines the PR changed; older code in the same file that predates these conventions is not a finding. Do not demand repository-wide cleanup. ## Imports and module namespaces @@ -31,11 +31,16 @@ Review changed TypeScript for the conventions below. They apply when a pull requ - Named imports stay correct for whole packages such as `@t3tools/contracts` and for modules used only for a pure helper, error, schema, config value, or type. Do not request `import type * as Contracts`. - When a barrel exposes a whole service module, prefer `export * as TokenStore from "./tokenStore.ts"` over individually renamed `make` and `layer` exports. +## Placement + +- Flag new or broadened feature logic in a transport handler: a WebSocket RPC handler in `apps/server/src/ws.ts`, an HTTP route handler, or an MCP tool handler. A handler decodes input, calls one service method, and maps the service's errors to the transport's error. Filesystem, Git, process, or persistence work, folder naming, multi-step command dispatch, retries, or rollback inside a handler belongs in a service method; ask for it to move to the domain's existing service, or a new one when none owns the domain. Existing inline handlers are legacy; flag only changed lines. +- Flag a new exported free function that does a server capability's effectful work (filesystem, Git, processes, persisted state) and is called from a handler, when it should be a service method. Plain functions for pure work (formatting, naming, parsing) are fine. + ## Service definition - One canonical module per service in this order: imports, error and schema declarations, the `Context.Service` tag with its interface inline, `make`, then `layer`. - Define the interface inline in `Context.Service`. Do not add a standalone `FooShape` interface; refer to the inferred type as `Foo["Service"]`. -- Export a real `make` when the module owns construction. Do not write `make = Effect.succeed(...)` only to force `Layer.effect`; use `Layer.succeed`, `Layer.scoped`, or whichever constructor matches. +- Define a real `make` when the module owns construction, and export it only when another module imports it; knip fails CI on an unused export, so do not ask for an export nothing uses. Do not write `make = Effect.succeed(...)` only to force `Layer.effect`; use `Layer.succeed`, `Layer.scoped`, or whichever constructor matches. - Use plain `make` and `layer` in a module named for its implementation (`BunPtyAdapter.ts`). Keep implementation-specific names when one abstract port module holds several implementations (`makeCloudflaredRelayClient`, `layerCloudflared` in `RelayClient.ts`). `infra/relay/src/db.ts` may keep its inline `Layer.succeed(RelayDb, db)`. - When a service moves, delete the old files and update every consumer, including orchestration, MCP, tests, and integration harnesses. Do not leave compatibility re-export shims. diff --git a/AGENTS.md b/AGENTS.md index 22e298879fc8..b926f276aba0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -69,6 +69,7 @@ The most common defect in this repo is a change that works on the path you teste - **Entry points.** A behavior reachable from the chat view is usually also reachable from Settings, the command palette, and a keybinding. Fixing one is not fixing the feature. - **Clients.** Web, desktop (wraps web, adds Electron shell/IPC), and mobile (React Native, separate navigation). Shared logic lives in `packages/client-runtime` - **Providers.** Codex, Claude, Cursor, Grok, OpenCode, and Antigravity each have an adapter. Provider-shaped features need a decision per adapter, even if the decision is "not supported here". +- **Agents.** A capability a user can trigger is usually one an agent should reach through MCP tools, and scheduled tasks run the same paths. That only works when it is a service method, not handler code. - **Contracts.** Anything crossing the wire is typed in `packages/contracts`. Change the schema and the server, web, mobile, and desktop all follow. - **Reverse states.** If you added a way in, add the way out and the way to see it. Snooze needs unsnooze. Close needs reopen. A one-way door is a bug. - **Connection modes.** Local, remote/relay, and tunnel behave differently. Multi-device and multi-environment cases are real. @@ -148,7 +149,7 @@ Full glossary with file links: `docs/internals/glossary.md` ## Where code lives -- `apps/server` - WebSocket, orchestration, providers, checkpointing. Effect-heavy: read `.repos/effect-smol/LLMS.md` before writing Effect code. +- `apps/server` - WebSocket, orchestration, providers, checkpointing. Effect-heavy: read [Effect services](docs/internals/effect-services.md) before adding server code, and `.repos/effect-smol/LLMS.md` for the Effect library itself. - `apps/web` - React/Vite UI. `apps/desktop` wraps it, `apps/mobile` is React Native, `apps/marketing` is the site. - `packages/contracts` - Effect/Schema contracts plus small derived helpers. No heavy runtime logic. - `packages/shared` - shared runtime utils, subpath exports, no barrel. @@ -158,6 +159,7 @@ Full glossary with file links: `docs/internals/glossary.md` ## Taste - Complexity belongs at the adapter boundary. Orchestration stays pure, UI stays dumb. +- Server features are services; transports stay thin. A `ws.ts` RPC handler, HTTP route, or MCP tool decodes input, calls one service method, and maps errors. See [Effect services](docs/internals/effect-services.md). - `apps/web/src/components/ui` exports own their look. Pick a `variant` or `size`; do not restyle one with `className`. If none fits and the look is a generic concept, add a variant to the component; a look that belongs to one feature stays in that feature's own component, not in `components/ui`. Layout classes (width, flex, margin, position) belong on the parent. `shadcn/no-restyle` fails lint on violations. - Inferred types over annotations. `any` is the enemy. - Comments describe how a thing is used, and move when the code moves. To be used mostly to describe functions, not to annotate every line of behavior. diff --git a/docs/internals/effect-services.md b/docs/internals/effect-services.md new file mode 100644 index 000000000000..7ae4671d2e6a --- /dev/null +++ b/docs/internals/effect-services.md @@ -0,0 +1,84 @@ +# Effect services + +Server features are Effect services. Transports call them: WebSocket RPC handlers in +[`ws.ts`](../../apps/server/src/ws.ts), HTTP routes, MCP tools, scheduled tasks, and the CLI. This +page holds the rules for writing them. The +[Effect Service Conventions](../../.macroscope/check-run-agents/effect-service-conventions.md) +review check enforces the same rules; keep the two in step. + +## Where a feature lives + +A server capability is a method on a service in its domain folder (`project/`, `workspace/`, `git/`, +`provider/`, ...). Extend the service that already owns the domain; add a new one only when none +does. + +A transport handler does three things: decode the request, call one service method, and map the +service's typed errors to the transport's error. Nothing else. Filesystem, Git, or process work, +folder naming, multi-step dispatch, retries, and rollback belong in the service. + +The reason is reach. Users trigger a capability from the WebSocket, agents reach it through MCP +tools, and scheduled tasks and the CLI run it too. Logic written into one handler is missing from +the others, and testing it needs a socket. Plain functions for pure work (a slug, an SVG, a +message) are fine next to the service; the capability itself is the method. + +```ts +// ws.ts: a thin handler +[WS_METHODS.projectsCreateNew]: (input) => + observeRpcEffect( + WS_METHODS.projectsCreateNew, + projectFolders.createNamedProject(input).pipe( + Effect.mapError((cause) => new ProjectCreateNewError({ cause })), + ), + { "rpc.aggregate": "orchestration" }, + ), +``` + +## Shape of a service module + +One module per service, in this order: imports, errors and schemas, the `Context.Service` tag with +its interface inline, `make`, then `layer`. [`WorkspacePaths.ts`](../../apps/server/src/workspace/WorkspacePaths.ts) +and [`T3ProjectFileLoader.ts`](../../apps/server/src/project/T3ProjectFileLoader.ts) are good +references. + +```ts +export class FooWriteError extends Schema.TaggedError()("FooWriteError", { + path: Schema.String, + cause: Schema.Defect(), +}) { + override get message(): string { + return "Failed to write the foo file."; + } +} + +export class Foo extends Context.Service< + Foo, + { readonly write: (input: { readonly path: string }) => Effect.Effect } +>()("t3/area/Foo") {} + +const make = Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + // ... + return Foo.of({ write }); +}); + +export const layer = Layer.effect(Foo, make); +``` + +- **Imports.** Consumers use the module as a namespace: `import * as Foo from "./Foo.ts"`, then + `yield* Foo.Foo` and `Foo.layer`. Never `import { layer as fooLayer }`. +- **Dependencies** come from the environment (`yield* FileSystem.FileSystem`), never as parameters to + `make`. +- **`make`** stays private unless another module imports it. Knip fails CI on an unused export. +- **Errors** are `Schema.TaggedError` classes with structured attributes and a `cause` when they wrap + a failure. The message is fixed or built from attributes, never from `cause`. Construct the error + where the failure happens; map it to a transport error only in the transport. Catch known tags + with `Effect.catchTags`. +- **Tests** exercise behavior through the service, with test layers only for external dependencies. + Don't mock the logic under test. + +## Before you push + +- Does any handler you touched do more than decode, call, and map errors? +- Could an agent (MCP) or a scheduled task use this capability? If not, is that deliberate? +- Did you extend the domain's existing service before adding a new one? +- Did you run knip? A new export with no importer fails it. From a3abb5266080c15b2a675d7f92b517b567c427e2 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 1 Oct 2026 14:10:50 -0700 Subject: [PATCH 16/32] fix(ci): pin eas-cli so mobile PR previews deploy again (#14659) Co-authored-by: Claude Opus 5.5 (1M context) --- .github/workflows/mobile-eas-preview.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/mobile-eas-preview.yml b/.github/workflows/mobile-eas-preview.yml index 5db69c9befaf..0af16fbf5a42 100644 --- a/.github/workflows/mobile-eas-preview.yml +++ b/.github/workflows/mobile-eas-preview.yml @@ -66,7 +66,10 @@ jobs: if: steps.expo-token.outputs.present == 'true' uses: expo/expo-github-action@v8 with: - eas-version: latest + # eas-cli 22 renamed `project` to `app` in build JSON, and + # continuous-deploy-fingerprint still reads `build.project.ownerAccount`. + # Unpin once https://github.com/expo/expo-github-action/issues/358 is fixed. + eas-version: 21.8.0 token: ${{ secrets.EXPO_TOKEN }} # npm, not pnpm: this only installs eas-cli into the action's own # tool dir, and pnpm 11 hard-fails that install on dtrace-provider's From 10ac2f2ba495508a2a2fd469e67eda5df73f0df1 Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 1 Oct 2026 16:48:29 -0700 Subject: [PATCH 17/32] fix(server): background GitHub polling uses ~74% fewer calls with batched GraphQL (#14673) Co-authored-by: Claude Opus 5.5 (1M context) --- apps/server/src/git/GitManager.test.ts | 26 + .../PullRequestSyncReactor.test.ts | 82 +++ .../orchestration/PullRequestSyncReactor.ts | 64 ++- .../orchestration/ThreadPullRequestReactor.ts | 4 +- .../src/pullRequest/GitHubPullRequestCli.ts | 7 +- .../src/pullRequest/PullRequestProvider.ts | 5 + .../src/pullRequest/PullRequestService.ts | 1 + .../pullRequest/gitHubPullRequestJson.test.ts | 38 ++ .../src/pullRequest/gitHubPullRequestJson.ts | 8 +- .../src/sourceControl/GitHubCli.test.ts | 331 +++++++++++- apps/server/src/sourceControl/GitHubCli.ts | 480 ++++++++++++++++-- .../GitHubSourceControlProvider.test.ts | 104 ++-- .../GitHubSourceControlProvider.ts | 69 +-- .../src/sourceControl/gitHubPullRequests.ts | 31 +- packages/contracts/src/pullRequest.ts | 2 + 15 files changed, 1039 insertions(+), 213 deletions(-) diff --git a/apps/server/src/git/GitManager.test.ts b/apps/server/src/git/GitManager.test.ts index 6a1a8c1510fa..2fceb0c41aa2 100644 --- a/apps/server/src/git/GitManager.test.ts +++ b/apps/server/src/git/GitManager.test.ts @@ -13,6 +13,7 @@ import * as Logger from "effect/Logger"; import * as Option from "effect/Option"; import * as PlatformError from "effect/PlatformError"; import * as References from "effect/References"; +import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; import * as Scope from "effect/Scope"; import { TestClock } from "effect/testing"; @@ -32,6 +33,7 @@ import { TextGenerationError, } from "@t3tools/contracts"; import * as GitHubCli from "../sourceControl/GitHubCli.ts"; +import { decodeGitHubPullRequestListJson } from "../sourceControl/gitHubPullRequests.ts"; import * as GitLabCli from "../sourceControl/GitLabCli.ts"; import * as TextGeneration from "../textGeneration/TextGeneration.ts"; import * as GitVcsDriver from "../vcs/GitVcsDriver.ts"; @@ -510,6 +512,30 @@ function createGitHubCliWithFakeGh(scenario: FakeGhScenario = {}): { return { service: { execute, + // The fake answers the CLI shape, so batched lookups read it the way the fallback does. + listPullRequestsByHead: (input) => + execute({ + cwd: input.cwd, + args: [ + "pr", + "list", + "--head", + input.headSelector, + "--state", + input.state, + "--limit", + String(input.limit), + "--json", + "number,title,url,baseRefName,headRefName,state,isDraft,mergedAt,closedAt,updatedAt,isCrossRepository,headRepository,headRepositoryOwner", + ], + }).pipe( + Effect.map((result) => { + const raw = result.stdout.trim(); + if (raw.length === 0) return []; + const decoded = decodeGitHubPullRequestListJson(raw); + return Result.isSuccess(decoded) ? decoded.success : []; + }), + ), listOpenPullRequests: (input) => execute({ cwd: input.cwd, diff --git a/apps/server/src/orchestration/PullRequestSyncReactor.test.ts b/apps/server/src/orchestration/PullRequestSyncReactor.test.ts index e6a18c2856a1..1339cd2e3cf4 100644 --- a/apps/server/src/orchestration/PullRequestSyncReactor.test.ts +++ b/apps/server/src/orchestration/PullRequestSyncReactor.test.ts @@ -754,6 +754,88 @@ describe("PullRequestSyncReactor", () => { ), ); + it.effect("reads a burst of requested links in one sweep", () => + Effect.scoped( + Effect.gen(function* () { + yield* TestClock.setTime(Date.parse(NOW)); + const reading = yield* Deferred.make(); + const release = yield* Deferred.make(); + const fixture = yield* makeHarness({ + snapshot: makeSnapshot([]), + summary: (input) => + Effect.gen(function* () { + if (input.number === 1) { + yield* Deferred.succeed(reading, undefined); + yield* Deferred.await(release); + } + return makeSummary(input); + }), + }); + yield* Effect.gen(function* () { + const reactor = yield* startAndSweep(fixture); + yield* Ref.set( + fixture.snapshots, + makeSnapshot( + [1, 2, 3, 4].map((number) => + makeThread(`thread-${number}`, { pullRequests: [makeLink(number)] }), + ), + ), + ); + const request = (number: number) => + reactor.requestSync({ host: "github.com", repository: "owner/repository", number }); + yield* request(1); + yield* Deferred.await(reading); + yield* Effect.forEach([2, 3, 4], request, { discard: true }); + yield* Deferred.succeed(release, undefined); + yield* reactor.drain; + // One sweep for the first link and one for the three that arrived while it read. + assert.strictEqual(yield* Queue.size(fixture.snapshotReads), 2); + assert.deepStrictEqual( + (yield* Ref.get(fixture.summaryCalls)).map((ref) => ref.number).toSorted(), + [1, 2, 3, 4], + ); + }).pipe(Effect.provide(fixture.layer)); + }), + ), + ); + + it.effect("skips the stack read for a pull request the summary places in no stack", () => + Effect.scoped( + Effect.gen(function* () { + yield* TestClock.setTime(Date.parse(NOW)); + const fixture = yield* makeHarness({ + snapshot: makeSnapshot([ + makeThread("unstacked", { pullRequests: [makeLink(1)] }), + makeThread("stacked", { pullRequests: [makeLink(2)] }), + makeThread("unknown", { pullRequests: [makeLink(3)] }), + ]), + summary: (input) => + Effect.succeed( + makeSummary( + input, + input.number === 1 + ? { stack: null } + : input.number === 2 + ? { stack: { number: 9, position: 1, size: 2, base: "main" } } + : {}, + ), + ), + }); + yield* Effect.gen(function* () { + yield* startAndSweep(fixture); + assert.deepStrictEqual( + (yield* Ref.get(fixture.stackCalls)).map((ref) => ref.number).toSorted(), + [2, 3], + ); + assert.deepStrictEqual( + (yield* Ref.get(fixture.syncCommands)).map((command) => command.number).toSorted(), + [1, 2, 3], + ); + }).pipe(Effect.provide(fixture.layer)); + }), + ), + ); + it.effect("polls open pull requests on settled threads every fifteen minutes", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/orchestration/PullRequestSyncReactor.ts b/apps/server/src/orchestration/PullRequestSyncReactor.ts index ffcc9fb3c26d..37bec97cc0e7 100644 --- a/apps/server/src/orchestration/PullRequestSyncReactor.ts +++ b/apps/server/src/orchestration/PullRequestSyncReactor.ts @@ -133,6 +133,9 @@ export const make = Effect.gen(function* () { const lastSyncedAt = new Map(); const requested = new Map(); let requestGeneration = 0; + // Requested keys wait in `requested` for one queued sweep, so a burst of links (an agent + // linking dozens of pull requests) is read together and shares the summary batches. + let requestedSweepQueued = false; const retryStacks = new Set(); const isDue = (key: string, entries: ReadonlyArray, nowMs: number): boolean => { @@ -151,7 +154,8 @@ export const make = Effect.gen(function* () { (cause: Cause.Cause): Effect.Effect => Cause.hasInterruptsOnly(cause) ? Effect.failCause(cause) : Effect.logWarning(message, fields); - const sweep = Effect.fn("PullRequestSyncReactor.sweep")(function* (requestedKey?: string) { + /** `requested` reads only keys asked for through `requestSync`; `all` is the periodic pass. */ + const sweep = Effect.fn("PullRequestSyncReactor.sweep")(function* (scope: "all" | "requested") { const threads = yield* snapshots.listThreadsWithPullRequests(); const now = yield* DateTime.now; const nowMs = DateTime.toEpochMillis(now); @@ -250,22 +254,31 @@ export const make = Effect.gen(function* () { retryStacks.has(key) || entries.some( (entry) => - entry.link.snapshot === null || !snapshotFieldsEqual(entry.link.snapshot, fields), + entry.link.snapshot === null || + !snapshotFieldsEqual(entry.link.snapshot, fields) || + (summary.stack !== undefined && + (entry.link.stack?.number ?? null) !== (summary.stack?.number ?? null)), ); - const fetchedStack = needsStack - ? yield* pullRequests.stack(ref, { includeDetails: false }).pipe( - Effect.map((stack) => ({ - stack: stack === null ? null : ({ kind: "native", ...stack } as const), - })), - Effect.catchCauseIf( - (cause) => !Cause.hasInterruptsOnly(cause), - () => - Effect.logWarning("pull request stack lookup failed", { - key, - }).pipe(Effect.as(null)), - ), - ) - : null; + // A summary that says the pull request is in no stack, for links that hold none, already + // answers what the stack read would. + const knownUnstacked = + summary.stack === null && entries.every((entry) => entry.link.stack === null); + const fetchedStack = !needsStack + ? null + : knownUnstacked + ? { stack: null } + : yield* pullRequests.stack(ref, { includeDetails: false }).pipe( + Effect.map((stack) => ({ + stack: stack === null ? null : ({ kind: "native", ...stack } as const), + })), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("pull request stack lookup failed", { + key, + }).pipe(Effect.as(null)), + ), + ); if (needsStack) { if (fetchedStack === null) { retryStacks.add(key); @@ -296,7 +309,7 @@ export const make = Effect.gen(function* () { yield* Effect.forEach( groups, ([key, entries]) => - (requestedKey === undefined || requestedKey === key) && isDue(key, entries, nowMs) + (scope === "all" || requested.has(key)) && isDue(key, entries, nowMs) ? syncGroup(key, entries).pipe( Effect.catchCause(logSkipped("pull request sync skipped", { key })), ) @@ -307,8 +320,12 @@ export const make = Effect.gen(function* () { ); }); - const worker = yield* makeDrainableWorker((key: string | undefined) => - sweep(key).pipe(Effect.catchCause(logSkipped("pull request sync sweep failed", {}))), + const worker = yield* makeDrainableWorker((scope: "all" | "requested") => + Effect.suspend(() => { + // Requests from here on queue another sweep; the ones already recorded are read by this. + if (scope === "requested") requestedSweepQueued = false; + return sweep(scope); + }).pipe(Effect.catchCause(logSkipped("pull request sync sweep failed", {}))), ); const start: PullRequestSyncReactor["Service"]["start"] = Effect.fn( @@ -322,7 +339,7 @@ export const make = Effect.gen(function* () { ); yield* forkParked( Effect.gen(function* () { - yield* worker.enqueue(undefined); + yield* worker.enqueue("all"); yield* worker.drain; }).pipe(Effect.repeat(Schedule.spaced("1 minute")), Effect.asVoid), ); @@ -330,9 +347,10 @@ export const make = Effect.gen(function* () { const requestSync: PullRequestSyncReactor["Service"]["requestSync"] = (key) => Effect.suspend(() => { - const syncKey = threadPullRequestKeyOf(key); - requested.set(syncKey, ++requestGeneration); - return worker.enqueue(syncKey); + requested.set(threadPullRequestKeyOf(key), ++requestGeneration); + if (requestedSweepQueued) return Effect.void; + requestedSweepQueued = true; + return worker.enqueue("requested"); }); return { start, drain: worker.drain, requestSync } satisfies PullRequestSyncReactor["Service"]; diff --git a/apps/server/src/orchestration/ThreadPullRequestReactor.ts b/apps/server/src/orchestration/ThreadPullRequestReactor.ts index 66ff81d5a9e7..3f8dfb82ece4 100644 --- a/apps/server/src/orchestration/ThreadPullRequestReactor.ts +++ b/apps/server/src/orchestration/ThreadPullRequestReactor.ts @@ -348,7 +348,9 @@ export const make = Effect.gen(function* () { }).pipe(Effect.tap(() => Effect.sync(() => failBackfill(group)))), ), ), - { concurrency: 8, discard: true }, + // Wide enough that a sweep's GitHub branch lookups reach GitHubCli together and share one + // GraphQL document, instead of one `gh pr list` per branch. + { concurrency: 32, discard: true }, ); }); diff --git a/apps/server/src/pullRequest/GitHubPullRequestCli.ts b/apps/server/src/pullRequest/GitHubPullRequestCli.ts index a609fd3d097b..c38a446c62eb 100644 --- a/apps/server/src/pullRequest/GitHubPullRequestCli.ts +++ b/apps/server/src/pullRequest/GitHubPullRequestCli.ts @@ -1821,7 +1821,12 @@ export const make = Effect.gen(function* () { const batchable = entries.filter( (entry) => buildPullRequestSummariesGraphQlQuery([entry.request]) !== null, ); - const query = buildPullRequestSummariesGraphQlQuery(batchable.map((entry) => entry.request)); + // Stack membership rides along where GitHub serves stacks, so the background sync can skip + // the REST stack read for pull requests that are in none. + const query = buildPullRequestSummariesGraphQlQuery( + batchable.map((entry) => entry.request), + first.request.host === "github.com", + ); const batched = query === null ? Effect.succeed(new Map()) diff --git a/apps/server/src/pullRequest/PullRequestProvider.ts b/apps/server/src/pullRequest/PullRequestProvider.ts index b4361c125c38..c21b40f50cab 100644 --- a/apps/server/src/pullRequest/PullRequestProvider.ts +++ b/apps/server/src/pullRequest/PullRequestProvider.ts @@ -116,6 +116,11 @@ export interface ProviderChangeRequestSummary { readonly reviewDecision?: PullRequestReviewDecision | null | undefined; readonly checksState?: PullRequestChecksState | null | undefined; readonly mergeability?: PullRequestMergeability | undefined; + /** + * The host-native stack the pull request sits in, from the same read. Null when the host says + * it is in none; absent when the read did not ask. + */ + readonly stack?: PullRequestStackMembership | null | undefined; } /** One layer of a host-native stack, bottom to top order is the array's. */ diff --git a/apps/server/src/pullRequest/PullRequestService.ts b/apps/server/src/pullRequest/PullRequestService.ts index 866a45e49b09..5d3be4593c23 100644 --- a/apps/server/src/pullRequest/PullRequestService.ts +++ b/apps/server/src/pullRequest/PullRequestService.ts @@ -1596,6 +1596,7 @@ export const make = Effect.gen(function* () { ...(changeRequest.mergeability === undefined ? {} : { mergeability: changeRequest.mergeability }), + ...(changeRequest.stack === undefined ? {} : { stack: changeRequest.stack }), })), ); }), diff --git a/apps/server/src/pullRequest/gitHubPullRequestJson.test.ts b/apps/server/src/pullRequest/gitHubPullRequestJson.test.ts index 7008ca739150..12239a2af0ee 100644 --- a/apps/server/src/pullRequest/gitHubPullRequestJson.test.ts +++ b/apps/server/src/pullRequest/gitHubPullRequestJson.test.ts @@ -1934,5 +1934,43 @@ describe("batched pull request summaries", () => { mergeability: "unknown", additions: 0, }); + // The document did not ask about stacks, so the summary does not claim an answer. + expect(decoded.success.get(0)).not.toHaveProperty("stack"); + }); + + it("reads stack membership only where the document asked for it", () => { + expect( + buildPullRequestSummariesGraphQlQuery([{ repository: "acme/web", number: 7 }], true), + ).toContain("stack { number size baseRefName } stackEntry { position }"); + expect( + buildPullRequestSummariesGraphQlQuery([{ repository: "acme/web", number: 7 }]), + ).not.toContain("stack {"); + const pullRequest = (number: number, stack: Record) => ({ + pullRequest: { + number, + title: "Stacked", + url: `https://github.com/acme/web/pull/${number}`, + headRefName: `feat/${number}`, + baseRefName: "main", + state: "OPEN", + updatedAt: "2026-08-24T00:00:00Z", + ...stack, + }, + }); + const decoded = expectSuccess( + decodePullRequestSummariesJson( + JSON.stringify({ + data: { + s0: pullRequest(7, { stack: null, stackEntry: null }), + s1: pullRequest(8, { + stack: { number: 3, size: 2, baseRefName: "main" }, + stackEntry: { position: 2 }, + }), + }, + }), + ), + ); + expect(decoded.get(0)?.stack).toBeNull(); + expect(decoded.get(1)?.stack).toEqual({ number: 3, size: 2, base: "main", position: 2 }); }); }); diff --git a/apps/server/src/pullRequest/gitHubPullRequestJson.ts b/apps/server/src/pullRequest/gitHubPullRequestJson.ts index 9be1b2a5844b..8e3a9ee330b8 100644 --- a/apps/server/src/pullRequest/gitHubPullRequestJson.ts +++ b/apps/server/src/pullRequest/gitHubPullRequestJson.ts @@ -1852,6 +1852,8 @@ export function decodePullRequestStatsJson( * shape as the search row where the two overlap: the checks arrive as GitHub's one-word rollup * rather than the whole check list `gh pr view` hands back, which is what keeps a batch cheap. */ +const STACK_MEMBERSHIP_SELECTION = "stack { number size baseRefName } stackEntry { position }"; + const PULL_REQUEST_SUMMARY_SELECTION = "number title url state isDraft mergeable reviewDecision additions deletions changedFiles " + "updatedAt mergedAt closedAt headRefName baseRefName " + @@ -1865,6 +1867,7 @@ const PULL_REQUEST_SUMMARY_SELECTION = */ export function buildPullRequestSummariesGraphQlQuery( changeRequests: ReadonlyArray<{ readonly repository: string; readonly number: number }>, + includeStacks = false, ): string | null { if (changeRequests.length === 0) return null; const selections: string[] = []; @@ -1874,7 +1877,7 @@ export function buildPullRequestSummariesGraphQlQuery( if (!REPOSITORY_PART.test(owner) || !REPOSITORY_PART.test(name)) return null; if (!Number.isSafeInteger(changeRequest.number) || changeRequest.number <= 0) return null; selections.push( - ` s${index}: repository(owner: "${owner}", name: "${name}") { pullRequest(number: ${changeRequest.number}) { ${PULL_REQUEST_SUMMARY_SELECTION} } }`, + ` s${index}: repository(owner: "${owner}", name: "${name}") { pullRequest(number: ${changeRequest.number}) { ${PULL_REQUEST_SUMMARY_SELECTION}${includeStacks ? ` ${STACK_MEMBERSHIP_SELECTION}` : ""} } }`, ); } return `query PullRequestSummaries {\n${selections.join("\n")}\n}`; @@ -1920,6 +1923,8 @@ export interface GitHubPullRequestSummary { readonly reviewDecision: PullRequestReviewDecision | null; readonly checksState: PullRequestChecksState | null; readonly mergeability: PullRequestMergeability; + /** Null when GitHub says the pull request is in no stack; absent when the read did not ask. */ + readonly stack?: PullRequestStackMembership | null; } /** @@ -1965,6 +1970,7 @@ export function decodePullRequestSummariesJson( }), ), mergeability: toMergeability(pr.mergeable), + ...(pr.stack === undefined ? {} : { stack: toStackMembership(pr) ?? null }), }); } return Result.succeed(summaries); diff --git a/apps/server/src/sourceControl/GitHubCli.test.ts b/apps/server/src/sourceControl/GitHubCli.test.ts index eb31572de467..8374a44af78f 100644 --- a/apps/server/src/sourceControl/GitHubCli.test.ts +++ b/apps/server/src/sourceControl/GitHubCli.test.ts @@ -4,6 +4,7 @@ import * as TestClock from "effect/testing/TestClock"; import * as Clock from "effect/Clock"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; +import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; import * as PlatformError from "effect/PlatformError"; import * as Redacted from "effect/Redacted"; @@ -31,13 +32,18 @@ const quotaOutput = (remaining = 5000, resetAt = "2099-01-01T00:00:00Z") => JSON.stringify({ data: { rateLimit: { cost: 1, limit: 5000, remaining, resetAt } } }), ); +const isBudgetReading = (input: VcsProcess.VcsProcessInput) => + input.args[0] === "api" && + input.args[1] === "graphql" && + input.args.at(-1)?.includes("rateLimit"); + const mockRun = vi.fn(); +// Budget readings are answered here, so `mockRun` sees only the commands under test. const layer = GitHubCli.layer.pipe( Layer.provide( Layer.mock(VcsProcess.VcsProcess)({ - run: (input) => - input.args[1] === "rate_limit" ? Effect.succeed(quotaOutput()) : mockRun(input), + run: (input) => (isBudgetReading(input) ? Effect.succeed(quotaOutput()) : mockRun(input)), }), ), ); @@ -46,9 +52,9 @@ afterEach(() => { mockRun.mockReset(); }); -it.effect("shares quota checks, preserves the reserve, and resumes after reset", () => +it.effect("reads the GraphQL budget once per window, preserves the reserve, and resumes", () => Effect.gen(function* () { - let probes = 0; + let readings = 0; const commands: string[] = []; let remaining = 501; let resetAt = DateTime.formatIso( @@ -58,8 +64,8 @@ it.effect("shares quota checks, preserves the reserve, and resumes after reset", Effect.provideService(VcsProcess.VcsProcess, { run: (input) => Effect.sync(() => { - if (input.args[1] === "rate_limit") { - probes++; + if (isBudgetReading(input)) { + readings++; assert.strictEqual(input.args[3], "enterprise.test"); return quotaOutput(remaining, resetAt); } @@ -79,24 +85,320 @@ it.effect("shares quota checks, preserves the reserve, and resumes after reset", yield* read("list"); const failure = yield* read("view").pipe(Effect.flip); assert.strictEqual(failure._tag, "GitHubCliRateLimitError"); - assert.strictEqual(probes, 1); assert.deepStrictEqual(commands, ["pr list"]); yield* read("view").pipe(Effect.provideService(GitHubCli.AllowGitHubReserve, true)); yield* gh.execute({ cwd: "/repo", args: ["pr", "merge", "1"] }); assert.deepStrictEqual(commands, ["pr list", "pr view", "pr merge"]); - remaining = 0; - yield* TestClock.adjust("30 seconds"); - yield* read("repo").pipe(Effect.flip); - assert.strictEqual(probes, 2); - yield* TestClock.adjust("30 seconds"); + // One reading covers the whole window. + assert.strictEqual(readings, 1); + yield* TestClock.adjust("1 minute"); remaining = 5000; resetAt = DateTime.formatIso(DateTime.makeUnsafe((yield* Clock.currentTimeMillis) + 60_000)); yield* Effect.all([read("list"), read("repo")], { concurrency: 2 }); - assert.strictEqual(probes, 3); + assert.strictEqual(readings, 2); assert.deepStrictEqual(commands.slice(3).toSorted(), ["pr list", "repo view"]); }).pipe(Effect.provide(Layer.merge(GitHubGraphQlBudget.layer, SourceControlRateLimit.layer))), ); +it.effect("reads the budget again at a near reset, and every ten minutes in a long window", () => + Effect.gen(function* () { + let readings = 0; + const startedAt = yield* Clock.currentTimeMillis; + let resetAt = DateTime.formatIso(DateTime.makeUnsafe(startedAt + 10_000)); + const gh = yield* GitHubCli.make.pipe( + Effect.provideService(VcsProcess.VcsProcess, { + run: (input) => + Effect.sync(() => { + if (!isBudgetReading(input)) return processOutput("[]"); + readings++; + return quotaOutput(5000, resetAt); + }), + }), + ); + const read = gh.execute({ cwd: "/repo", args: ["pr", "list"] }); + yield* read; + // The window resets ten seconds in, so the reading expires with it. + resetAt = DateTime.formatIso(DateTime.makeUnsafe(startedAt + 10_000 + 3_600_000)); + yield* TestClock.adjust("10 seconds"); + yield* read; + assert.strictEqual(readings, 2); + yield* TestClock.adjust("9 minutes"); + yield* read; + assert.strictEqual(readings, 2); + yield* TestClock.adjust("1 minute"); + yield* read; + assert.strictEqual(readings, 3); + }).pipe(Effect.provide(Layer.merge(GitHubGraphQlBudget.layer, SourceControlRateLimit.layer))), +); + +it.effect("reads anyway when the budget reading fails", () => + Effect.gen(function* () { + const gh = yield* GitHubCli.make.pipe( + Effect.provideService(VcsProcess.VcsProcess, { + run: (input) => + isBudgetReading(input) + ? Effect.fail( + new VcsProcessSpawnError({ + operation: "GitHubCli.execute", + command: "gh", + cwd: "/gone", + cause: new Error("ENOENT"), + }), + ) + : Effect.succeed(processOutput("[]")), + }), + ); + const result = yield* gh.execute({ cwd: "/repo", args: ["pr", "list"] }); + assert.strictEqual(result.stdout, "[]"); + }).pipe(Effect.provide(Layer.merge(GitHubGraphQlBudget.layer, SourceControlRateLimit.layer))), +); + +describe("selectGitHubBaseRepository", () => { + const remotes = (...entries: ReadonlyArray) => + entries + .flatMap(([name, url]) => [`${name}\t${url} (fetch)`, `${name}\t${url} (push)`]) + .join("\n"); + const select = (input: { remotes: string; resolved?: string }) => + GitHubCli.selectGitHubBaseRepository({ resolved: "", host: "github.com", ...input }); + + it("picks the repository gh reads without a prompt", () => { + assert.deepStrictEqual(select({ remotes: remotes(["fork", "git@github.com:me/web.git"]) }), { + owner: "me", + name: "web", + }); + const fork = remotes( + ["origin", "git@github.com:me/web.git"], + ["upstream", "https://github.com/Acme/Web.git"], + ); + assert.deepStrictEqual(select({ remotes: fork }), { owner: "acme", name: "web" }); + assert.deepStrictEqual(select({ remotes: fork, resolved: "remote.origin.gh-resolved base" }), { + owner: "me", + name: "web", + }); + assert.deepStrictEqual( + select({ remotes: fork, resolved: "remote.origin.gh-resolved acme/other" }), + { owner: "acme", name: "other" }, + ); + // gh ranks remote names in any case. + assert.deepStrictEqual( + select({ + remotes: remotes( + ["origin", "git@github.com:me/web.git"], + ["Upstream", "git@github.com:acme/web.git"], + ), + }), + { owner: "acme", name: "web" }, + ); + }); + + it("leaves gh to choose when it might weigh the remotes differently", () => { + for (const input of [ + { remotes: "" }, + { + remotes: remotes(["a", "git@github.com:me/web.git"], ["b", "git@github.com:acme/web.git"]), + }, + { + remotes: remotes( + ["origin", "git@github.com:me/web.git"], + ["mirror", "git@gitlab.com:me/web.git"], + ), + }, + { remotes: remotes(["origin", "git@github-work:me/web.git"]) }, + { + remotes: remotes( + ["origin", "git@github.com:me/web.git"], + ["Origin", "git@github.com:acme/web.git"], + ), + }, + { + remotes: remotes( + ["origin", "git@github.com:me/web.git"], + ["upstream", "git@github.com:acme/web.git"], + ), + resolved: "remote.origin.gh-resolved base\nremote.upstream.gh-resolved base", + }, + ]) { + assert.strictEqual(select(input), null); + } + }); +}); + +describe("GitHubCli.listPullRequestsByHead", () => { + const remoteOutput = + "origin\tgit@github.com:acme/web.git (fetch)\norigin\tgit@github.com:acme/web.git (push)\n"; + const node = (number: number, headRefName: string) => ({ + number, + title: `PR ${number}`, + url: `https://github.com/acme/web/pull/${number}`, + baseRefName: "main", + headRefName, + state: "MERGED", + mergedAt: "2026-01-01T00:00:00Z", + updatedAt: "2026-01-02T00:00:00Z", + headRepository: { name: "web", nameWithOwner: "acme/web" }, + headRepositoryOwner: { login: "acme" }, + }); + const decodeRequest = Schema.decodeSync( + Schema.fromJsonString( + Schema.Struct({ + query: Schema.String, + variables: Schema.Record(Schema.String, Schema.Unknown), + }), + ), + ); + const jsonOutput = (value: unknown) => processOutput(JSON.stringify(value)); + const git = (input: VcsProcess.VcsProcessInput) => + input.args[0] === "remote" + ? processOutput(remoteOutput) + : { ...processOutput(""), exitCode: ChildProcessSpawner.ExitCode(1) }; + + it.effect("reads heads on one repository in one GraphQL document", () => + Effect.gen(function* () { + const documents: Array<{ query: string; variables: Record }> = []; + mockRun.mockImplementation((input) => + Effect.sync(() => { + if (input.command === "git") return git(input); + documents.push(decodeRequest(input.stdin ?? "")); + return jsonOutput({ + data: { + repository: { h0: { nodes: [node(7, "feature/a")] }, h1: { nodes: [] } }, + rateLimit: { cost: 1, limit: 5000, remaining: 4999, resetAt: "2099-01-01T00:00:00Z" }, + }, + }); + }), + ); + const gh = yield* GitHubCli.GitHubCli; + const lookups = yield* Effect.all( + ["feature/a", "feature/b"].map((headSelector) => + gh.listPullRequestsByHead({ + cwd: "/repo", + headSelector, + state: "all", + limit: 100, + rateLimitHost: "github.com", + }), + ), + { concurrency: "unbounded" }, + ).pipe(Effect.forkChild); + yield* TestClock.adjust("50 millis"); + const [first, second] = yield* Fiber.join(lookups); + assert.deepStrictEqual( + first?.map((pr) => [pr.number, pr.state, pr.headRepositoryNameWithOwner]), + [[7, "merged", "acme/web"]], + ); + assert.deepStrictEqual(second, []); + assert.strictEqual(documents.length, 1); + assert.include(documents[0]!.query, "rateLimit"); + assert.deepStrictEqual(documents[0]!.variables, { + owner: "acme", + name: "web", + h0: "feature/a", + s0: ["OPEN", "CLOSED", "MERGED"], + h1: "feature/b", + s1: ["OPEN", "CLOSED", "MERGED"], + }); + }).pipe(Effect.provide(layer)), + ); + + it.effect("asks gh pr list when gh could read another repository", () => + Effect.gen(function* () { + const commands: Array> = []; + mockRun.mockImplementation((input) => + Effect.sync(() => { + commands.push([input.command, ...input.args]); + if (input.command === "git") { + return processOutput( + input.args[0] === "remote" + ? "a\tgit@github.com:me/web.git (fetch)\nb\tgit@github.com:acme/web.git (fetch)\n" + : "", + ); + } + return input.args[3] === "feature/empty" + ? processOutput("") + : jsonOutput([node(8, "feature/a")]); + }), + ); + const gh = yield* GitHubCli.GitHubCli; + const pullRequests = yield* gh.listPullRequestsByHead({ + cwd: "/repo", + headSelector: "feature/a", + state: "all", + limit: 100, + rateLimitHost: "github.com", + }); + assert.deepStrictEqual( + pullRequests.map((pr) => pr.number), + [8], + ); + assert.deepStrictEqual(commands.at(-1), [ + "gh", + "pr", + "list", + "--head", + "feature/a", + "--state", + "all", + "--limit", + "100", + "--json", + "number,title,url,baseRefName,headRefName,state,isDraft,mergedAt,closedAt,updatedAt,isCrossRepository,headRepository,headRepositoryOwner", + ]); + const empty = yield* gh.listPullRequestsByHead({ + cwd: "/repo", + headSelector: "feature/empty", + state: "all", + limit: 100, + rateLimitHost: "github.com", + }); + assert.deepStrictEqual(empty, []); + }).pipe(Effect.provide(layer)), + ); + + it.effect("fails a rate-limited document whole instead of asking head by head", () => + Effect.gen(function* () { + let ghCalls = 0; + mockRun.mockImplementation((input) => { + if (input.command === "git") return Effect.succeed(git(input)); + ghCalls++; + return Effect.fail( + new VcsProcessExitError({ + operation: "GitHubCli.execute", + command: "gh", + cwd: "/repo", + exitCode: 1, + failureKind: "rate-limited", + detail: "API rate limit exceeded.", + stderrLength: 24, + stderrTruncated: false, + }), + ); + }); + const gh = yield* GitHubCli.GitHubCli; + const lookups = yield* Effect.all( + ["feature/a", "feature/b"].map((headSelector) => + gh + .listPullRequestsByHead({ + cwd: "/repo", + headSelector, + state: "all", + limit: 100, + rateLimitHost: "github.com", + }) + .pipe(Effect.flip), + ), + { concurrency: "unbounded" }, + ).pipe(Effect.forkChild); + yield* TestClock.adjust("50 millis"); + const errors = yield* Fiber.join(lookups); + assert.deepStrictEqual( + errors.map((error) => error._tag), + ["GitHubCliRateLimitError", "GitHubCliRateLimitError"], + ); + assert.strictEqual(ghCalls, 1); + }).pipe(Effect.provide(layer)), + ); +}); + describe("GitHubCli.layer", () => { it.effect("shares the registry budget with CLI reads through nested layer providers", () => Effect.gen(function* () { @@ -116,8 +418,9 @@ describe("GitHubCli.layer", () => { Effect.provideService(VcsProcess.VcsProcess, { run: (input) => Effect.sync(() => { - if (input.args[1] === "rate_limit") + if (isBudgetReading(input)) { return quotaOutput(input.env?.GH_TOKEN === "empty" ? 0 : 5000); + } reads++; return processOutput("[]"); }), diff --git a/apps/server/src/sourceControl/GitHubCli.ts b/apps/server/src/sourceControl/GitHubCli.ts index c525740efeae..f1973d1f2a33 100644 --- a/apps/server/src/sourceControl/GitHubCli.ts +++ b/apps/server/src/sourceControl/GitHubCli.ts @@ -1,4 +1,5 @@ import * as Cache from "effect/Cache"; +import * as Clock from "effect/Clock"; import * as Duration from "effect/Duration"; import * as Exit from "effect/Exit"; import * as Context from "effect/Context"; @@ -8,6 +9,8 @@ import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as PlatformError from "effect/PlatformError"; import * as Redacted from "effect/Redacted"; +import * as Request from "effect/Request"; +import * as RequestResolver from "effect/RequestResolver"; import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; @@ -16,11 +19,14 @@ import { type SourceControlRepositoryVisibility, type VcsError, } from "@t3tools/contracts"; +import { normalizeGitRemoteUrl } from "@t3tools/shared/git"; +import { decodeJsonResult } from "@t3tools/shared/schemaJson"; import * as VcsProcess from "../vcs/VcsProcess.ts"; import * as GitHubGraphQlBudget from "./githubGraphQlBudget.ts"; import * as SourceControlRateLimit from "./SourceControlRateLimit.ts"; import { + decodeGitHubPullRequestEntries, decodeGitHubPullRequestJson, decodeGitHubPullRequestListJson, type NormalizedGitHubPullRequestRecord, @@ -300,6 +306,20 @@ export class GitHubCli extends Context.Service< readonly rateLimitHost?: string; }) => Effect.Effect, GitHubCliError>; + /** + * Pull requests whose head is `headSelector`, in the repository `gh pr list` would read in + * `cwd`. Lookups on one repository that arrive together share one GraphQL document; a + * checkout whose repository gh could pick another way is asked through `gh pr list`. + */ + readonly listPullRequestsByHead: (input: { + readonly cwd: string; + readonly headSelector: string; + readonly state: "open" | "closed" | "merged" | "all"; + readonly limit: number; + /** The checkout's GitHub host. Without it the lookup is not batched. */ + readonly rateLimitHost?: string; + }) => Effect.Effect, GitHubCliError>; + readonly getPullRequest: (input: { readonly cwd: string; readonly reference: string; @@ -394,6 +414,149 @@ function deriveRepositoryCloneUrlsFromCreateOutput( }; } +type PullRequestListState = "open" | "closed" | "merged" | "all"; + +const PULL_REQUEST_LIST_JSON_FIELDS = + "number,title,url,baseRefName,headRefName,state,isDraft,mergedAt,closedAt,updatedAt,isCrossRepository,headRepository,headRepositoryOwner"; +/** The `gh pr list --json` fields above, as GraphQL selects them. */ +const PULL_REQUEST_NODE_SELECTION = + "number title url baseRefName headRefName state isDraft mergedAt closedAt updatedAt isCrossRepository headRepository { name nameWithOwner } headRepositoryOwner { login }"; +const GRAPHQL_STATES: Record> = { + open: ["OPEN"], + closed: ["CLOSED"], + merged: ["MERGED"], + all: ["OPEN", "CLOSED", "MERGED"], +}; +/** + * Head lookups per GraphQL document. A document of a hundred costs one point, the same as one + * `gh pr list`, but half that keeps each answer near half a second. + */ +const HEAD_LOOKUPS_PER_DOCUMENT = 50; +/** + * How long a head lookup waits for company. Branch discovery reaches GitHub only after each + * branch's own git reads, so lookups started together arrive tens of milliseconds apart. + */ +const HEAD_LOOKUP_BATCH_WINDOW = "50 millis"; +/** A full document is 5,000 rows of well under 2 KB each. */ +const HEAD_LOOKUP_MAX_OUTPUT_BYTES = 16_000_000; +const RATE_LIMIT_READING = "query { rateLimit { cost limit remaining resetAt } }"; + +class PullRequestsByHeadRead extends Request.Class< + { + readonly cwd: string; + readonly host: string; + readonly owner: string; + readonly name: string; + readonly headRefName: string; + readonly state: PullRequestListState; + readonly limit: number; + }, + ReadonlyArray, + GitHubCliError +> {} + +const GraphQlVariables = Schema.Record( + Schema.String, + Schema.Union([Schema.String, Schema.Array(Schema.String)]), +); +/** A GraphQL request body for `gh api graphql --input -`. */ +const encodeGraphQlRequest = Schema.encodeSync( + Schema.fromJsonString(Schema.Struct({ query: Schema.String, variables: GraphQlVariables })), +); + +/** One aliased `pullRequests` connection per lookup, each head and state passed as a variable. */ +function buildPullRequestsByHeadQuery( + lookups: ReadonlyArray>, +): { readonly document: string; readonly variables: typeof GraphQlVariables.Type } { + const variables: Record> = {}; + const declarations: string[] = ["$owner: String!", "$name: String!"]; + const selections: string[] = []; + for (const [index, lookup] of lookups.entries()) { + variables[`h${index}`] = lookup.headRefName; + variables[`s${index}`] = GRAPHQL_STATES[lookup.state]; + declarations.push(`$h${index}: String!`, `$s${index}: [PullRequestState!]`); + // `gh pr list` orders the same way, so a head with more matches than the limit keeps the + // same rows. + selections.push( + ` h${index}: pullRequests(headRefName: $h${index}, states: $s${index}, first: ${lookup.limit}, orderBy: { field: CREATED_AT, direction: DESC }) { nodes { ${PULL_REQUEST_NODE_SELECTION} } }`, + ); + } + return { + document: `query PullRequestsByHead(${declarations.join(", ")}) {\n repository(owner: $owner, name: $name) {\n${selections.join("\n")}\n }\n}`, + variables, + }; +} + +/** The reset time of a `rateLimit` reading, which sets when the next one is due. */ +const decodeRateLimitReading = (raw: string) => + Result.map( + decodeJsonResult( + Schema.Struct({ + data: Schema.Struct({ rateLimit: Schema.Struct({ resetAt: Schema.String }) }), + }), + )(raw), + (reading) => reading.data.rateLimit.resetAt, + ); + +const decodePullRequestsByHead = decodeJsonResult( + Schema.Struct({ + data: Schema.Struct({ + repository: Schema.Record( + Schema.String, + Schema.NullOr(Schema.Struct({ nodes: Schema.Array(Schema.Unknown) })), + ), + }), + }), +); + +/** + * The repository `gh pr list` reads in a checkout, picked the way gh picks one without a + * prompt: the remote `gh repo set-default` marked, else the first of upstream, github, origin + * (in any case), else the only remote. `remotes` is `git remote -v` output and `resolved` is the output of + * `git config --get-regexp '^remote\..*\.gh-resolved$'`. + * + * Null whenever gh might weigh the remotes differently: a remote on another host or under an + * SSH alias, more than one mark, or several remotes with none of those names. Callers then + * ask gh itself. + */ +export function selectGitHubBaseRepository(input: { + readonly remotes: string; + readonly resolved: string; + readonly host: string; +}): { readonly owner: string; readonly name: string } | null { + const host = input.host.toLowerCase(); + const repositories = new Map(); + for (const line of input.remotes.split("\n")) { + const match = /^(\S+)\s+(\S+)\s+\(fetch\)$/u.exec(line.trim()); + if (!match) continue; + const [remoteHost, owner, name, ...rest] = normalizeGitRemoteUrl(match[2]!).split("/"); + if (remoteHost !== host || !owner || !name || rest.length > 0) return null; + repositories.set(match[1]!, { owner, name }); + } + const marks = input.resolved + .split("\n") + .map((line) => /^remote\.(.+)\.gh-resolved\s+(\S+)$/u.exec(line.trim())) + .filter((match): match is RegExpExecArray => match !== null && repositories.has(match[1]!)); + if (marks.length > 1) return null; + const [mark] = marks; + if (mark) { + if (mark[2] === "base") return repositories.get(mark[1]!) ?? null; + const [owner, name, ...rest] = mark[2]!.toLowerCase().split("/"); + return owner && name && rest.length === 0 ? { owner, name } : null; + } + // gh sorts remotes by these names, case-insensitively, and takes the first. A tie for the + // top place has no defined winner. + const score = (remoteName: string) => + ["origin", "github", "upstream"].indexOf(remoteName.toLowerCase()) + 1; + const ranked = [...repositories.entries()].toSorted( + ([left], [right]) => score(right) - score(left), + ); + const [top, next] = ranked; + return top !== undefined && (next === undefined || score(top[0]) > score(next[0])) + ? top[1] + : null; +} + /** @public Service construction is part of the canonical Effect module API. */ export const make = Effect.gen(function* () { const process = yield* VcsProcess.VcsProcess; @@ -438,66 +601,86 @@ export const make = Effect.gen(function* () { }, ); - const quota = yield* Cache.makeWith( + /** + * A GraphQL `rateLimit` reading per host and credential, so the budget knows the balance + * before reads that cannot report their own cost (`gh pr list`). GraphQL documents keep it + * current in between. Each reading costs one point and is redone at the reset, or after ten + * minutes so a `gh auth switch` is not priced against the old account for a whole hour. + */ + const budgetReading = yield* Cache.makeWith( (key: string) => { const host = key.split("\0")[0]!; return executeRaw({ cwd: globalThis.process.cwd(), - args: [ - "api", - "rate_limit", - "--hostname", - host, - "--jq", - ".resources.graphql | {data:{rateLimit:{cost:1,limit:.limit,remaining:.remaining,resetAt:(.reset|todateiso8601)}}}", - ], + args: ["api", "graphql", "--hostname", host, "-f", `query=${RATE_LIMIT_READING}`], }).pipe( Effect.tap((result) => budget.observe(host, result.stdout)), - Effect.asVoid, + Effect.flatMap((result) => + Clock.currentTimeMillis.pipe( + Effect.map((now) => { + const resetAtMs = Date.parse( + decodeRateLimitReading(result.stdout).pipe( + Result.match({ onFailure: () => "", onSuccess: (reading) => reading }), + ), + ); + // A reset that is missing or already past (a skewed clock) waits a minute, so a + // bad reading cannot ask again on every read. + return Duration.millis( + Number.isFinite(resetAtMs) && resetAtMs > now + ? Math.min(resetAtMs - now, 600_000) + : 60_000, + ); + }), + ), + ), ); }, { capacity: 32, - timeToLive: (exit) => (Exit.isSuccess(exit) ? Duration.seconds(30) : Duration.zero), + timeToLive: (exit) => (Exit.isSuccess(exit) ? exit.value : Duration.minutes(1)), }, ); - const execute: GitHubCli["Service"]["execute"] = Effect.fn("GitHubCli.execute")( - function* (input) { - const [command, action] = input.args; - if ( - !( - (command === "pr" && (action === "list" || action === "view")) || - (command === "repo" && action === "view") - ) - ) - return yield* executeRaw(input); + + /** + * Runs a GraphQL-priced read under its host's pause and the GraphQL budget. `run` receives + * the document with `rateLimit` added, so a GraphQL read can report what it spent; a CLI read + * ignores it and is priced at one point. + */ + const guardedRead = (input: { + readonly cwd: string; + readonly host: string; + readonly document: string; + readonly allowReserve: boolean; + readonly run: (document: string) => Effect.Effect; + }) => + Effect.gen(function* () { const credential = yield* PinnedGitHubCredential; - if (credential !== null && !targetsVerifiedHost(input.args, credential.host)) - return yield* executeRaw(input); - const allowReserve = input.allowReserve ?? (yield* AllowGitHubReserve); - const host = ( - credential?.host ?? - commandHosts(input.args).find((host) => host !== null) ?? - input.rateLimitHost ?? - input.env?.GH_HOST ?? - globalThis.process.env.GH_HOST ?? - "github.com" - ).toLowerCase(); - const key = { provider: "github" as const, host }; + const key = { provider: "github" as const, host: input.host }; const guarded = Effect.gen(function* () { - const lease = yield* limits.check(key, allowReserve ? { allowPaused: true } : undefined); - return yield* Effect.gen(function* () { - yield* Cache.get(quota, `${host}\0${credential?.credentialFingerprint ?? ""}`); - yield* budget.query(host, "query {}", allowReserve ? { allowReserve: true } : undefined); - return yield* executeRaw(input); - }).pipe( - Effect.tap(() => limits.recordSuccess({ ...key, lease })), - Effect.tapError((error) => - error._tag === "GitHubCliRateLimitError" - ? limits.recordRateLimit({ ...key, lease }) - : Effect.void, - ), + const lease = yield* limits.check( + key, + input.allowReserve ? { allowPaused: true } : undefined, ); + // A failed reading leaves the budget unknown; it never blocks the read itself. + yield* Cache.get( + budgetReading, + `${input.host}\0${yield* SourceControlRateLimit.CredentialScope}`, + ).pipe(Effect.ignore); + return yield* budget + .query( + input.host, + input.document, + input.allowReserve ? { allowReserve: true } : undefined, + ) + .pipe( + Effect.flatMap(input.run), + Effect.tap(() => limits.recordSuccess({ ...key, lease })), + Effect.tapError((error) => + error._tag === "GitHubCliRateLimitError" + ? limits.recordRateLimit({ ...key, lease }) + : Effect.void, + ), + ); }); return yield* guarded.pipe( Effect.provideService( @@ -516,11 +699,218 @@ export const make = Effect.gen(function* () { ), }), ); + }); + + const execute: GitHubCli["Service"]["execute"] = Effect.fn("GitHubCli.execute")( + function* (input) { + const [command, action] = input.args; + if ( + !( + (command === "pr" && (action === "list" || action === "view")) || + (command === "repo" && action === "view") + ) + ) + return yield* executeRaw(input); + const credential = yield* PinnedGitHubCredential; + if (credential !== null && !targetsVerifiedHost(input.args, credential.host)) + return yield* executeRaw(input); + return yield* guardedRead({ + cwd: input.cwd, + host: ( + credential?.host ?? + commandHosts(input.args).find((host) => host !== null) ?? + input.rateLimitHost ?? + input.env?.GH_HOST ?? + globalThis.process.env.GH_HOST ?? + "github.com" + ).toLowerCase(), + document: "query {}", + allowReserve: input.allowReserve ?? (yield* AllowGitHubReserve), + run: () => executeRaw(input), + }); + }, + ); + + const listPullRequestsWithCli = (input: { + readonly cwd: string; + readonly headSelector: string; + readonly state: PullRequestListState; + readonly limit: number; + readonly rateLimitHost?: string | undefined; + }) => + execute({ + cwd: input.cwd, + ...(input.rateLimitHost === undefined ? {} : { rateLimitHost: input.rateLimitHost }), + args: [ + "pr", + "list", + "--head", + input.headSelector, + "--state", + input.state, + "--limit", + String(input.limit), + "--json", + PULL_REQUEST_LIST_JSON_FIELDS, + ], + }).pipe( + Effect.flatMap((result) => { + const raw = result.stdout.trim(); + if (raw.length === 0) return Effect.succeed([]); + const decoded = decodeGitHubPullRequestListJson(raw); + return Result.isSuccess(decoded) + ? Effect.succeed(decoded.success) + : Effect.fail( + new GitHubChangeRequestListDecodeError({ + command: "gh", + cwd: input.cwd, + cause: decoded.failure, + }), + ); + }), + ); + + const git = (cwd: string, args: ReadonlyArray) => + process.run({ + operation: "GitHubCli.baseRepository", + command: "git", + args, + cwd, + allowNonZeroExit: true, + timeoutMs: 5_000, + }); + + /** The repository gh reads in `cwd`, or null when gh could pick it another way. */ + const resolveBaseRepository = (cwd: string, host: string) => + globalThis.process.env.GH_REPO + ? Effect.succeed(null) + : Effect.all([ + git(cwd, ["remote", "-v"]), + git(cwd, ["config", "--get-regexp", "^remote\\..*\\.gh-resolved$"]), + ]).pipe( + Effect.map(([remotes, resolved]) => + remotes.exitCode === 0 + ? selectGitHubBaseRepository({ + remotes: remotes.stdout, + resolved: resolved.exitCode === 0 ? resolved.stdout : "", + host, + }) + : null, + ), + Effect.orElseSucceed(() => null), + ); + + const headResolver = RequestResolver.makeGrouped({ + key: ({ request, context }) => + JSON.stringify([ + request.host, + request.owner, + request.name, + Context.getOrElse(context, PinnedGitHubCredential, () => null)?.credentialFingerprint ?? + null, + Context.getOrElse(context, SourceControlRateLimit.CredentialScope, () => ""), + ]), + resolver: (entries) => { + const [first] = entries; + const { cwd, host, owner, name } = first.request; + const query = buildPullRequestsByHeadQuery(entries.map((entry) => entry.request)); + const readCli = (entry: (typeof entries)[number]) => + listPullRequestsWithCli({ + cwd: entry.request.cwd, + headSelector: entry.request.headRefName, + state: entry.request.state, + limit: entry.request.limit, + rateLimitHost: entry.request.host, + }).pipe( + Effect.exit, + Effect.map((exit) => entry.completeUnsafe(exit)), + ); + return guardedRead({ + cwd, + host, + document: query.document, + allowReserve: false, + run: (document) => + executeRaw({ + cwd, + args: ["api", "graphql", "--hostname", host, "--input", "-"], + // Up to 50 heads of 100 rows each. A default branch such as `main` can match a + // hundred fork pull requests, so the 1 MB default would cut the answer short. + maxOutputBytes: HEAD_LOOKUP_MAX_OUTPUT_BYTES, + stdin: encodeGraphQlRequest({ + query: document, + variables: { owner, name, ...query.variables }, + }), + }).pipe(Effect.tap((result) => budget.observe(host, result.stdout))), + }).pipe( + Effect.flatMap((result) => { + const decoded = decodePullRequestsByHead(result.stdout); + if (!Result.isSuccess(decoded)) { + return Effect.forEach(entries, readCli, { discard: true }); + } + const aliases = decoded.success.data.repository; + return Effect.forEach( + entries, + (entry, index) => { + const alias = aliases[`h${index}`]; + if (alias == null) return readCli(entry); + entry.completeUnsafe(Exit.succeed(decodeGitHubPullRequestEntries(alias.nodes))); + return Effect.void; + }, + { discard: true }, + ); + }), + // A document GitHub refused as a whole (a renamed repository, a field an older + // Enterprise host lacks) leaves each lookup to gh. A rate limit fails them all: + // asking one at a time would only spend what the pause is saving. + Effect.catchIf( + (error) => error._tag !== "GitHubCliRateLimitError", + () => Effect.forEach(entries, readCli, { discard: true }), + ), + Effect.catchCause((cause) => + Effect.sync(() => { + for (const entry of entries) entry.completeUnsafe(Exit.failCause(cause)); + }), + ), + ); }, + }).pipe( + RequestResolver.setDelay(HEAD_LOOKUP_BATCH_WINDOW), + RequestResolver.batchN(HEAD_LOOKUPS_PER_DOCUMENT), ); + const listPullRequestsByHead: GitHubCli["Service"]["listPullRequestsByHead"] = Effect.fn( + "GitHubCli.listPullRequestsByHead", + )(function* (input) { + const host = input.rateLimitHost?.toLowerCase(); + const credential = yield* PinnedGitHubCredential; + // `owner:branch` selectors and other hosts keep gh's own handling. + const repository = + host === undefined || + input.headSelector.includes(":") || + (credential !== null && credential.host !== host) + ? null + : yield* resolveBaseRepository(input.cwd, host); + if (host === undefined || repository === null) { + return yield* listPullRequestsWithCli(input); + } + return yield* Effect.request( + new PullRequestsByHeadRead({ + cwd: input.cwd, + host, + owner: repository.owner, + name: repository.name, + headRefName: input.headSelector, + state: input.state, + limit: Math.min(Math.max(Math.trunc(input.limit), 1), 100), + }), + headResolver, + ); + }); + return GitHubCli.of({ execute, + listPullRequestsByHead, listOpenPullRequests: (input) => execute({ cwd: input.cwd, diff --git a/apps/server/src/sourceControl/GitHubSourceControlProvider.test.ts b/apps/server/src/sourceControl/GitHubSourceControlProvider.test.ts index 0d46b6eab9ea..2a214fc800ff 100644 --- a/apps/server/src/sourceControl/GitHubSourceControlProvider.test.ts +++ b/apps/server/src/sourceControl/GitHubSourceControlProvider.test.ts @@ -7,6 +7,7 @@ import { ChildProcessSpawner } from "effect/unstable/process"; import * as VcsProcess from "../vcs/VcsProcess.ts"; import * as GitHubCli from "./GitHubCli.ts"; +import * as GitHubGraphQlBudget from "./githubGraphQlBudget.ts"; import { parseGitHubAuthStatus } from "./gitHubAuthStatus.ts"; import * as GitHubSourceControlProvider from "./GitHubSourceControlProvider.ts"; @@ -32,19 +33,13 @@ function makeProvider(github: Partial) { it.effect("uses the enterprise quota for a current-repository default branch read", () => Effect.gen(function* () { - const provider = yield* GitHubSourceControlProvider.make.pipe( - Effect.provide(GitHubCli.layer), - Effect.provideService(VcsProcess.VcsProcess, { - run: (input) => - Effect.sync(() => { - if (input.args[1] !== "rate_limit") return processResult("main"); - assert.strictEqual(input.args[3], "enterprise.test"); - return processResult( - '{"data":{"rateLimit":{"cost":1,"limit":5000,"remaining":5000,"resetAt":"2099-01-01T00:00:00Z"}}}', - ); - }), - }), + // github.com is out of quota; the enterprise read must not be priced against it. + const budget = yield* GitHubGraphQlBudget.GitHubGraphQlBudget; + yield* budget.observe( + "github.com", + '{"data":{"rateLimit":{"cost":1,"limit":5000,"remaining":0,"resetAt":"2099-01-01T00:00:00Z"}}}', ); + const provider = yield* GitHubSourceControlProvider.make; const branch = yield* provider.getDefaultBranch({ cwd: "/enterprise-repo", context: { @@ -54,7 +49,12 @@ it.effect("uses the enterprise quota for a current-repository default branch rea }, }); assert.strictEqual(branch, "main"); - }), + }).pipe( + Effect.provide(GitHubCli.layer), + Effect.provideService(VcsProcess.VcsProcess, { + run: () => Effect.succeed(processResult("main")), + }), + ), ); it.effect("maps GitHub PR summaries into provider-neutral change requests", () => @@ -138,50 +138,47 @@ it.effect("adds safe request context while retaining GitHub CLI causes", () => }), ); -it.effect("uses gh json listing for non-open change request state queries", () => +it.effect("lists change request history through the batched head lookup", () => Effect.gen(function* () { - let executeArgs: ReadonlyArray = []; + let lookup: Parameters[0] | null = + null; const provider = yield* makeProvider({ - execute: (input) => { - executeArgs = input.args; - return Effect.succeed( - processResult( - JSON.stringify([ - { - number: 7, - title: "Merged work", - url: "https://github.com/pingdotgg/t3code/pull/7", - baseRefName: "main", - headRefName: "feature/merged", - state: "merged", - mergedAt: "2026-01-01T00:00:00Z", - updatedAt: "2026-01-02T00:00:00.000Z", - }, - ]), - ), - ); + listPullRequestsByHead: (input) => { + lookup = input; + return Effect.succeed([ + { + number: 7, + title: "Merged work", + url: "https://enterprise.test/acme/web/pull/7", + baseRefName: "main", + headRefName: "feature/merged", + state: "merged", + mergedAt: "2026-01-01T00:00:00Z", + updatedAt: Option.some(DateTime.makeUnsafe("2026-01-02T00:00:00.000Z")), + }, + ]); }, }); const changeRequests = yield* provider.listChangeRequests({ cwd: "/repo", + context: { + provider: { kind: "github", name: "GitHub Enterprise", baseUrl: "https://enterprise.test" }, + remoteName: "origin", + remoteUrl: "https://enterprise.test/acme/web.git", + }, headSelector: "feature/merged", state: "all", limit: 10, }); - assert.deepStrictEqual(executeArgs, [ - "pr", - "list", - "--head", - "feature/merged", - "--state", - "all", - "--limit", - "10", - "--json", - "number,title,url,baseRefName,headRefName,state,isDraft,mergedAt,closedAt,updatedAt,isCrossRepository,headRepository,headRepositoryOwner", - ]); + assert.deepStrictEqual(lookup, { + cwd: "/repo", + headSelector: "feature/merged", + state: "all", + limit: 10, + rateLimitHost: "enterprise.test", + }); assert.strictEqual(changeRequests[0]?.provider, "github"); assert.strictEqual(changeRequests[0]?.state, "merged"); assert.strictEqual(changeRequests[0]?.mergedAt, "2026-01-01T00:00:00Z"); @@ -192,23 +189,6 @@ it.effect("uses gh json listing for non-open change request state queries", () = }), ); -it.effect("treats empty non-open change request listing output as no results", () => - Effect.gen(function* () { - const provider = yield* makeProvider({ - execute: () => Effect.succeed(processResult("")), - }); - - const changeRequests = yield* provider.listChangeRequests({ - cwd: "/repo", - headSelector: "feature/empty", - state: "all", - limit: 10, - }); - - assert.deepStrictEqual(changeRequests, []); - }), -); - it.effect("creates GitHub PRs through provider-neutral input names", () => Effect.gen(function* () { let createInput: Parameters[0] | null = diff --git a/apps/server/src/sourceControl/GitHubSourceControlProvider.ts b/apps/server/src/sourceControl/GitHubSourceControlProvider.ts index 372d2a032d79..905146d5a733 100644 --- a/apps/server/src/sourceControl/GitHubSourceControlProvider.ts +++ b/apps/server/src/sourceControl/GitHubSourceControlProvider.ts @@ -2,16 +2,10 @@ import * as Schema from "effect/Schema"; import * as DateTime from "effect/DateTime"; import * as Effect from "effect/Effect"; import * as Option from "effect/Option"; -import * as Result from "effect/Result"; -import { - SourceControlProviderError, - type ChangeRequest, - type ChangeRequestState, -} from "@t3tools/contracts"; +import { SourceControlProviderError, type ChangeRequest } from "@t3tools/contracts"; import * as GitHubCli from "./GitHubCli.ts"; import { findAuthenticatedGitHubAccount, parseGitHubAuthStatus } from "./gitHubAuthStatus.ts"; -import { decodeGitHubPullRequestListJson } from "./gitHubPullRequests.ts"; import * as SourceControlProvider from "./SourceControlProvider.ts"; import { combinedAuthOutput, @@ -151,59 +145,28 @@ export const make = Effect.gen(function* () { ); } - const stateArg: ChangeRequestState | "all" = input.state; return github - .execute({ + .listPullRequestsByHead({ cwd: input.cwd, + headSelector: input.headSelector, + state: input.state, + limit: input.limit ?? 20, ...(input.context === undefined ? {} : { rateLimitHost: new URL(input.context.provider.baseUrl).host }), - args: [ - "pr", - "list", - "--head", - input.headSelector, - "--state", - stateArg, - "--limit", - String(input.limit ?? 20), - "--json", - "number,title,url,baseRefName,headRefName,state,isDraft,mergedAt,closedAt,updatedAt,isCrossRepository,headRepository,headRepositoryOwner", - ], }) .pipe( - Effect.flatMap((result) => { - const raw = result.stdout.trim(); - if (raw.length === 0) { - return Effect.succeed([]); - } - return Effect.sync(() => decodeGitHubPullRequestListJson(raw)).pipe( - Effect.flatMap((decoded) => - Result.isSuccess(decoded) - ? Effect.succeed( - decoded.success.map((item) => { - const { updatedAt, ...summary } = item; - return { - ...toChangeRequest({ - ...summary, - ...(Option.isSome(updatedAt) - ? { updatedAt: DateTime.formatIso(updatedAt.value) } - : {}), - }), - updatedAt, - }; - }), - ) - : Effect.fail( - new GitHubCli.GitHubChangeRequestListDecodeError({ - command: "gh", - cwd: input.cwd, - cause: decoded.failure, - }), - ), - ), - ); - }), + Effect.map((items) => + items.map(({ updatedAt, ...summary }) => ({ + ...toChangeRequest({ + ...summary, + ...(Option.isSome(updatedAt) + ? { updatedAt: DateTime.formatIso(updatedAt.value) } + : {}), + }), + updatedAt, + })), + ), Effect.mapError( (error) => new SourceControlProviderError({ diff --git a/apps/server/src/sourceControl/gitHubPullRequests.ts b/apps/server/src/sourceControl/gitHubPullRequests.ts index b233d900adf1..c29a3806e13d 100644 --- a/apps/server/src/sourceControl/gitHubPullRequests.ts +++ b/apps/server/src/sourceControl/gitHubPullRequests.ts @@ -114,25 +114,30 @@ const decodeGitHubPullRequestList = decodeJsonResult(Schema.Array(Schema.Unknown const decodeGitHubPullRequest = decodeJsonResult(GitHubPullRequestSchema); const decodeGitHubPullRequestEntry = Schema.decodeUnknownExit(GitHubPullRequestSchema); +/** + * Pull request rows in `gh --json` or GraphQL node shape. A row that does not decode is + * skipped, so one malformed pull request cannot hide the rest. + */ +export function decodeGitHubPullRequestEntries( + entries: ReadonlyArray, +): ReadonlyArray { + const pullRequests: NormalizedGitHubPullRequestRecord[] = []; + for (const entry of entries) { + const decodedEntry = decodeGitHubPullRequestEntry(entry); + if (Exit.isSuccess(decodedEntry)) { + pullRequests.push(normalizeGitHubPullRequestRecord(decodedEntry.value)); + } + } + return pullRequests; +} + export function decodeGitHubPullRequestListJson( raw: string, ): Result.Result< ReadonlyArray, Cause.Cause > { - const result = decodeGitHubPullRequestList(raw); - if (Result.isSuccess(result)) { - const pullRequests: NormalizedGitHubPullRequestRecord[] = []; - for (const entry of result.success) { - const decodedEntry = decodeGitHubPullRequestEntry(entry); - if (Exit.isFailure(decodedEntry)) { - continue; - } - pullRequests.push(normalizeGitHubPullRequestRecord(decodedEntry.value)); - } - return Result.succeed(pullRequests); - } - return Result.fail(result.failure); + return Result.map(decodeGitHubPullRequestList(raw), decodeGitHubPullRequestEntries); } export function decodeGitHubPullRequestJson( diff --git a/packages/contracts/src/pullRequest.ts b/packages/contracts/src/pullRequest.ts index 7a249cefb373..3470aaa7a5c7 100644 --- a/packages/contracts/src/pullRequest.ts +++ b/packages/contracts/src/pullRequest.ts @@ -747,6 +747,8 @@ export const PullRequestSummary = Schema.Struct({ reviewDecision: Schema.optional(Schema.NullOr(PullRequestReviewDecision)), checksState: Schema.optional(Schema.NullOr(PullRequestChecksState)), mergeability: Schema.optional(PullRequestMergeability), + /** Null when the host says the pull request is in no stack; absent when the read did not ask. */ + stack: Schema.optional(Schema.NullOr(PullRequestStackMembership)), }); export type PullRequestSummary = typeof PullRequestSummary.Type; From 67f640093ffea1adaa585949d87e4bc2010b0810 Mon Sep 17 00:00:00 2001 From: Chris Deeming Date: Fri, 2 Oct 2026 00:58:29 +0100 Subject: [PATCH 18/32] fix(web): show the Docker icon on dockerfile code blocks (#14675) --- apps/web/src/pierre-icons.test.ts | 5 +++++ apps/web/src/pierre-icons.ts | 11 +++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/web/src/pierre-icons.test.ts b/apps/web/src/pierre-icons.test.ts index 5f5aca691e99..6090d7ed9e72 100644 --- a/apps/web/src/pierre-icons.test.ts +++ b/apps/web/src/pierre-icons.test.ts @@ -56,7 +56,12 @@ describe("Pierre file icons", () => { it("normalizes common markdown fence language aliases", () => { assert.equal(syntheticFileNameForLanguageId("typescript"), "file.ts"); + assert.equal(syntheticFileNameForLanguageId("dockerfile"), "Dockerfile"); assert.equal(syntheticFileNameForLanguageId("shellscript"), "file.sh"); assert.equal(syntheticFileNameForLanguageId("python"), "file.py"); }); + + it("gives a dockerfile fence the Docker icon", () => { + assert.isTrue(hasSpecificPierreIconForFileName(syntheticFileNameForLanguageId("dockerfile"))); + }); }); diff --git a/apps/web/src/pierre-icons.ts b/apps/web/src/pierre-icons.ts index 49aec9cc4cef..46f0099fedee 100644 --- a/apps/web/src/pierre-icons.ts +++ b/apps/web/src/pierre-icons.ts @@ -51,7 +51,6 @@ const completeIconResolver = createFileTreeIconResolver(T3_PIERRE_ICONS); const LANGUAGE_EXTENSION_ALIASES: Record = { bash: "sh", csharp: "cs", - dockerfile: "dockerfile", javascript: "js", jsx: "jsx", markdown: "md", @@ -79,9 +78,17 @@ export function inferEntryKindFromPath(pathValue: string): "file" | "directory" return base.includes(".") ? "file" : "directory"; } +/** Languages whose files are recognised by name rather than by extension. */ +const LANGUAGE_FILE_NAMES: Record = { + dockerfile: "Dockerfile", +}; + export function syntheticFileNameForLanguageId(languageId: string): string { const normalized = languageId.toLowerCase(); - return `file.${LANGUAGE_EXTENSION_ALIASES[normalized] ?? normalized}`; + return ( + LANGUAGE_FILE_NAMES[normalized] ?? + `file.${LANGUAGE_EXTENSION_ALIASES[normalized] ?? normalized}` + ); } export function resolvePierreIconForEntry( From 0a04cc50def48121b9ece038c7df8b7fa789074b Mon Sep 17 00:00:00 2001 From: Theo Browne Date: Thu, 1 Oct 2026 17:04:27 -0700 Subject: [PATCH 19/32] feat(web): update providers on every machine with one click (#14678) Co-authored-by: Claude Opus 5.5 (1M context) --- ...iderUpdateLaunchNotification.logic.test.ts | 88 ++++++++++++++ .../ProviderUpdateLaunchNotification.logic.ts | 56 +++++++++ .../src/components/ProviderUpdatesAction.tsx | 112 ++++++++++++++++++ .../settings/ProviderSettingsPanel.tsx | 2 + docs/user/updating.md | 7 ++ 5 files changed, 265 insertions(+) create mode 100644 apps/web/src/components/ProviderUpdatesAction.tsx diff --git a/apps/web/src/components/ProviderUpdateLaunchNotification.logic.test.ts b/apps/web/src/components/ProviderUpdateLaunchNotification.logic.test.ts index c55338cd5c46..5e27fa901f0e 100644 --- a/apps/web/src/components/ProviderUpdateLaunchNotification.logic.test.ts +++ b/apps/web/src/components/ProviderUpdateLaunchNotification.logic.test.ts @@ -21,6 +21,7 @@ import { getProviderUpdateInitialToastView, getProviderUpdateProgressToastView, getProviderUpdateRejectedToastView, + getProviderUpdateRunToastView, getProviderUpdateSidebarPillView, hasOneClickUpdateProviderCandidate, isProviderUpdateCandidate, @@ -1058,3 +1059,90 @@ it("does not offer incompatible latest versions and restores suggestions after p expect(isProviderSettingsUpdateCandidate(snapshot)).toBe(expected); } }); + +describe("getProviderUpdateRunToastView", () => { + const updateState = ( + status: "succeeded" | "failed", + message: string, + ): ServerProvider["updateState"] => ({ + status, + startedAt: checkedAt, + finishedAt: laterCheckedAt, + message, + output: null, + }); + const run = ( + machineLabel: string, + providerDriver: string, + result: Parameters[0][number]["result"], + ) => ({ + machineLabel, + driver: driver(providerDriver), + instanceId: instanceId(providerDriver), + result, + }); + + it("lists every failed update and ignores interrupted ones", () => { + const view = getProviderUpdateRunToastView([ + run( + "Mac Studio", + "codex", + AsyncResult.success({ + providers: [ + provider({ + driver: driver("codex"), + updateState: updateState("succeeded", "Provider updated."), + }), + ], + }), + ), + run( + "Mac Studio", + "claudeAgent", + AsyncResult.success({ + providers: [ + provider({ + driver: driver("claudeAgent"), + updateState: updateState("failed", "npm exited with code 1."), + }), + ], + }), + ), + run("Laptop", "codex", AsyncResult.failure(Cause.die(new Error("WebSocket closed")))), + run("Server", "codex", AsyncResult.failure(Cause.interrupt())), + ]); + + expect(view).toEqual({ + type: "error", + title: "2 of 3 provider updates failed", + description: "Mac Studio · Claude: npm exited with code 1.\nLaptop · Codex: WebSocket closed", + }); + }); + + it("reports success when every update succeeded", () => { + const succeeded = AsyncResult.success({ + providers: [ + provider({ + driver: driver("codex"), + updateState: updateState("succeeded", "Provider updated."), + }), + ], + }); + + expect( + getProviderUpdateRunToastView([ + run("Mac Studio", "codex", succeeded), + run("Laptop", "codex", succeeded), + ]), + ).toEqual({ + type: "success", + title: "2 providers updated", + description: "New sessions will use the updated providers.", + }); + expect( + getProviderUpdateRunToastView([ + run("Server", "codex", AsyncResult.failure(Cause.interrupt())), + ]), + ).toBeNull(); + }); +}); diff --git a/apps/web/src/components/ProviderUpdateLaunchNotification.logic.ts b/apps/web/src/components/ProviderUpdateLaunchNotification.logic.ts index dd7b25a62cad..e245fcb7cf30 100644 --- a/apps/web/src/components/ProviderUpdateLaunchNotification.logic.ts +++ b/apps/web/src/components/ProviderUpdateLaunchNotification.logic.ts @@ -8,6 +8,7 @@ import { type ServerProvider, } from "@t3tools/contracts"; import { + isAtomCommandInterrupted, squashAtomCommandFailure, type AtomCommandResult, } from "@t3tools/client-runtime/state/runtime"; @@ -330,6 +331,61 @@ export function getProviderUpdateProgressToastView(input: { return getProviderUpdateRunningToastView(input.providerCount); } +/** One provider update sent by the cross-machine "Update all", with its result. */ +export interface ProviderUpdateRun { + readonly machineLabel: string; + readonly driver: ProviderDriverKind; + readonly instanceId: ProviderInstanceId; + readonly result: AtomCommandResult< + { readonly providers: ReadonlyArray }, + unknown + >; +} + +/** + * Summarize a cross-machine "Update all" as one toast, or null when every + * request was interrupted. Each update that did not succeed gets its own line, + * so a failure on one machine is not hidden by successes on the others. + */ +export function getProviderUpdateRunToastView( + runs: ReadonlyArray, +): Pick | null { + const settled = runs.filter((run) => !isAtomCommandInterrupted(run.result)); + if (settled.length === 0) { + return null; + } + const failureLines = settled.flatMap((run) => { + const label = `${run.machineLabel} · ${PROVIDER_DISPLAY_NAMES[run.driver] ?? run.driver}`; + if (run.result._tag === "Failure") { + const error = squashAtomCommandFailure(run.result); + return [`${label}: ${error instanceof Error ? error.message : "Provider update failed."}`]; + } + const updateState = run.result.value.providers.find( + (provider) => provider.instanceId === run.instanceId, + )?.updateState; + return updateState?.status === "succeeded" + ? [] + : [`${label}: ${updateState?.message ?? "Provider update did not finish."}`]; + }); + if (failureLines.length === 0) { + return { + type: "success", + title: settled.length === 1 ? "Provider updated" : `${settled.length} providers updated`, + description: getProviderUpdatedDescription(settled.length), + }; + } + return { + type: "error", + title: + failureLines.length < settled.length + ? `${failureLines.length} of ${settled.length} provider updates failed` + : settled.length === 1 + ? "Provider update failed" + : "Provider updates failed", + description: failureLines.join("\n"), + }; +} + export function collectUpdatedProviderSnapshots(input: { readonly results: ReadonlyArray< AtomCommandResult<{ readonly providers: ReadonlyArray }, unknown> diff --git a/apps/web/src/components/ProviderUpdatesAction.tsx b/apps/web/src/components/ProviderUpdatesAction.tsx new file mode 100644 index 000000000000..fe435b5833ef --- /dev/null +++ b/apps/web/src/components/ProviderUpdatesAction.tsx @@ -0,0 +1,112 @@ +import { PROVIDER_DISPLAY_NAMES } from "@t3tools/contracts"; +import { useMemo, useRef, useState } from "react"; + +import { useEnvironments } from "~/state/environments"; +import { serverEnvironment } from "~/state/server"; +import { useAtomCommand } from "~/state/use-atom-command"; +import { + canOneClickUpdateProviderCandidate, + collectProviderUpdateCandidates, + getProviderUpdateRunToastView, + type ProviderUpdateRun, +} from "./ProviderUpdateLaunchNotification.logic"; +import { Button } from "./ui/button"; +import { stackedThreadToast, toastManager } from "./ui/toast"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; + +/** + * Updates every outdated provider on every connected machine at once, then + * reports the results in one toast. Each server queues updates that share an + * installer, so sending them all together is safe. The server still checks + * permissions: a session that cannot operate a machine gets a failure line for + * it. Renders nothing when no machine has a one-click update. + */ +export function ProviderUpdatesAction() { + const { environments } = useEnvironments(); + const updateProvider = useAtomCommand(serverEnvironment.updateProvider, { + reportFailure: false, + }); + const pending = useRef(false); + const [isPending, setIsPending] = useState(false); + const machines = useMemo( + () => + environments.flatMap((environment) => { + const providers = environment.serverConfig?.providers ?? []; + if (environment.connection.phase !== "connected") { + return []; + } + const candidates = collectProviderUpdateCandidates(providers).filter((candidate) => + canOneClickUpdateProviderCandidate(candidate, providers), + ); + return candidates.length > 0 + ? [{ environmentId: environment.environmentId, label: environment.label, candidates }] + : []; + }), + [environments], + ); + // Candidates leave the list as soon as their servers report them queued, so + // keep the button while the run is in flight. + if (machines.length === 0 && !isPending) { + return null; + } + + const handleUpdate = async () => { + if (pending.current) return; + pending.current = true; + setIsPending(true); + try { + const runs = await Promise.all( + machines.flatMap(({ environmentId, label, candidates }) => + candidates.map(async (candidate): Promise => ({ + machineLabel: label, + driver: candidate.driver, + instanceId: candidate.instanceId, + result: await updateProvider({ + environmentId, + input: { provider: candidate.driver, instanceId: candidate.instanceId }, + }), + })), + ), + ); + const view = getProviderUpdateRunToastView(runs); + if (view) { + toastManager.add( + stackedThreadToast({ + ...view, + description: {view.description}, + }), + ); + } + } finally { + pending.current = false; + setIsPending(false); + } + }; + + return ( + + void handleUpdate()} + > + {isPending ? "Updating…" : "Update all"} + + } + /> + + {machines.map((machine) => ( +