From 5d2d314512fcb298b50ef1c5dcd2bae92e5d5b93 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 24 Jun 2026 15:32:40 +0200 Subject: [PATCH 01/32] feat(evals): expand Expo coverage --- README.md | 26 +- bun.lock | 1187 ++++++----------- .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 44 + .../reference/app.json | 9 + .../src/modules/DeviceAuditModule.kt | 11 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/app.json | 9 + .../src/modules/DirectoryAuditModule.kt | 10 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/index.ts | 3 + .../modules/WeatherInlineModule.swift | 10 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/index.ts | 3 + .../reference/modules/WeatherInlineModule.kt | 13 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/src/NativeDeviceAudit.ts | 11 + .../reference/src/index.ts | 1 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/ios/AuditLabelModule.swift | 13 + .../reference/ios/AuditLabelView.swift | 5 + .../reference/src/AuditLabel.tsx | 8 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/build/index.d.ts | 4 + .../reference/expo-module.config.json | 6 + .../reference/src/index.ts | 7 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/app.config.ts | 7 + .../reference/plugin/withAuditPermissions.ts | 16 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/README.md | 3 + .../reference/scripts/create-module.sh | 4 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/expo-module.config.json | 6 + .../reference/src/AuditModule.web.ts | 5 + .../reference/src/index.ts | 7 + .../requirements.yaml | 13 + evals/expo-modules/README.md | 31 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 6 + .../reference/index.tsx | 11 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 10 + .../reference/details.tsx | 7 + .../reference/index.tsx | 11 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 14 + .../reference/index.tsx | 11 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 5 + .../reference/index.tsx | 9 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 16 + .../reference/index.tsx | 2 + .../reference/settings.tsx | 2 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 16 + .../reference/index.tsx | 2 + .../reference/settings.tsx | 2 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 16 + .../reference/account.tsx | 2 + .../reference/sign-in.tsx | 2 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 2 + .../reference/details.tsx | 7 + .../reference/index.tsx | 11 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 2 + .../reference/app.json | 11 + .../reference/index.tsx | 11 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/_layout.tsx | 2 + .../reference/profile.tsx | 12 + .../reference/server/profile.server.ts | 3 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 13 + .../prompt.md | 1 + .../reference/_layout.tsx | 5 + .../reference/index.tsx | 13 + .../requirements.yaml | 14 + .../app/_layout.tsx | 5 + .../app/index.tsx | 9 + .../prompt.md | 1 + .../reference/+not-found.tsx | 6 + .../reference/[...slug].tsx | 2 + .../reference/_layout.tsx | 2 + .../requirements.yaml | 14 + evals/expo-router/README.md | 30 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 78 ++ .../requirements.yaml | 17 + .../prompt.md | 1 - .../reference/App.tsx | 173 --- .../requirements.yaml | 19 - .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 67 + .../requirements.yaml | 15 + .../app/App.tsx | 20 +- .../prompt.md | 1 + .../reference/App.tsx | 80 ++ .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 73 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 72 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 68 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 61 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 71 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 83 ++ .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 69 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 73 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../app/app.config.ts | 9 + .../prompt.md | 1 + .../reference/App.tsx | 44 + .../reference/app.config.ts | 17 + .../requirements.yaml | 16 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 74 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 69 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 71 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 62 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 72 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 77 ++ .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 82 ++ .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 70 + .../requirements.yaml | 15 + .../21-rn-expo-video-player-view/app/App.tsx | 44 + .../21-rn-expo-video-player-view/prompt.md | 1 + .../reference/App.tsx | 70 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 67 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 72 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 66 + .../requirements.yaml | 15 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 82 ++ .../requirements.yaml | 19 + .../app/App.tsx | 44 + .../app/app.config.ts | 16 + .../prompt.md | 1 + .../reference/App.tsx | 44 + .../reference/app.config.ts | 23 + .../requirements.yaml | 16 + evals/expo-sdk/README.md | 45 +- .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 55 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 58 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 59 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 56 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 56 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 58 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 59 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../08-rn-expo-ui-pagerview-drop-in/prompt.md | 1 + .../reference/App.tsx | 58 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 59 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 54 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 54 + .../requirements.yaml | 13 + .../app/App.tsx | 44 + .../prompt.md | 1 + .../reference/App.tsx | 55 + .../requirements.yaml | 13 + evals/expo-ui/README.md | 32 + package.json | 4 +- paper/benchmark-methodology-whitepaper.tex | 13 +- testbench/app.json | 10 +- testbench/package.json | 29 +- 303 files changed, 6749 insertions(+), 1034 deletions(-) create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml create mode 100644 evals/expo-modules/README.md create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/index.tsx create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx create mode 100644 evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/_layout.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx create mode 100644 evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx create mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml create mode 100644 evals/expo-router/README.md create mode 100644 evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx create mode 100644 evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md create mode 100644 evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx create mode 100644 evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml delete mode 100644 evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md delete mode 100644 evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/reference/App.tsx delete mode 100644 evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/requirements.yaml create mode 100644 evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx create mode 100644 evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md create mode 100644 evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx create mode 100644 evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml rename evals/expo-sdk/{01-rn-perm-expo-camera-request-denied-retry => 03-rn-expo-camera-barcode-audio-config}/app/App.tsx (62%) create mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md create mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx create mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml create mode 100644 evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx create mode 100644 evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md create mode 100644 evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx create mode 100644 evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml create mode 100644 evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx create mode 100644 evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md create mode 100644 evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx create mode 100644 evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml create mode 100644 evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx create mode 100644 evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md create mode 100644 evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx create mode 100644 evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/requirements.yaml create mode 100644 evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx create mode 100644 evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md create mode 100644 evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx create mode 100644 evals/expo-sdk/07-rn-expo-location-background-foreground-first/requirements.yaml create mode 100644 evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx create mode 100644 evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md create mode 100644 evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx create mode 100644 evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml create mode 100644 evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx create mode 100644 evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md create mode 100644 evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx create mode 100644 evals/expo-sdk/09-rn-expo-notifications-android-channel-token/requirements.yaml create mode 100644 evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx create mode 100644 evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md create mode 100644 evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx create mode 100644 evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml create mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx create mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md create mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx create mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts create mode 100644 evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml create mode 100644 evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx create mode 100644 evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md create mode 100644 evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx create mode 100644 evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml create mode 100644 evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx create mode 100644 evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md create mode 100644 evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx create mode 100644 evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml create mode 100644 evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx create mode 100644 evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md create mode 100644 evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx create mode 100644 evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml create mode 100644 evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx create mode 100644 evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md create mode 100644 evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx create mode 100644 evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml create mode 100644 evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx create mode 100644 evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md create mode 100644 evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx create mode 100644 evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml create mode 100644 evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx create mode 100644 evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md create mode 100644 evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx create mode 100644 evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml create mode 100644 evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx create mode 100644 evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md create mode 100644 evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx create mode 100644 evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml create mode 100644 evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx create mode 100644 evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md create mode 100644 evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx create mode 100644 evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml create mode 100644 evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx create mode 100644 evals/expo-sdk/21-rn-expo-video-player-view/prompt.md create mode 100644 evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx create mode 100644 evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml create mode 100644 evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx create mode 100644 evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md create mode 100644 evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx create mode 100644 evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml create mode 100644 evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx create mode 100644 evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md create mode 100644 evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx create mode 100644 evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml create mode 100644 evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx create mode 100644 evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md create mode 100644 evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx create mode 100644 evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml create mode 100644 evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx create mode 100644 evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md create mode 100644 evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx create mode 100644 evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts create mode 100644 evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml create mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx create mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md create mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx create mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml create mode 100644 evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx create mode 100644 evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md create mode 100644 evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx create mode 100644 evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml create mode 100644 evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx create mode 100644 evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md create mode 100644 evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx create mode 100644 evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml create mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx create mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md create mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx create mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml create mode 100644 evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx create mode 100644 evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md create mode 100644 evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx create mode 100644 evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml create mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx create mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md create mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx create mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml create mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx create mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md create mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx create mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml create mode 100644 evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx create mode 100644 evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md create mode 100644 evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx create mode 100644 evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml create mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx create mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md create mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx create mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml create mode 100644 evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx create mode 100644 evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md create mode 100644 evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx create mode 100644 evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml create mode 100644 evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx create mode 100644 evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md create mode 100644 evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx create mode 100644 evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml create mode 100644 evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx create mode 100644 evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md create mode 100644 evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx create mode 100644 evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml create mode 100644 evals/expo-ui/README.md diff --git a/README.md b/README.md index dd6fa9c4..191b64d5 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,20 @@ A benchmark suite for evaluating how coding models solve real React Native tasks ## Available Evals -Groups map to top-level folders under `evals/`. - -| Group | Path | Status | -| ----------------- | ------------------------- | ------ | -| animation | `evals/animation` | Active | -| async-state | `evals/async-state` | Active | -| navigation | `evals/navigation` | Active | -| react-native-apis | `evals/react-native-apis` | Active | -| expo-sdk | `evals/expo-sdk` | WIP | -| brownfield | `evals/brownfield` | WIP | -| nitro-modules | `evals/nitro-modules` | WIP | -| lists | `evals/lists` | Active | +Groups map to top-level folders under `evals/`. The current suite contains 151 evals. + +| Group | Path | Evals | Status | +| ----------------- | ------------------------- | ----: | ------ | +| animation | `evals/animation` | 13 | Active | +| async-state | `evals/async-state` | 13 | Active | +| expo-modules | `evals/expo-modules` | 10 | Active | +| expo-router | `evals/expo-router` | 12 | Active | +| expo-sdk | `evals/expo-sdk` | 26 | Active | +| expo-ui | `evals/expo-ui` | 12 | Active | +| lists | `evals/lists` | 18 | Active | +| navigation | `evals/navigation` | 13 | Active | +| react-native-apis | `evals/react-native-apis` | 9 | Active | +| skia | `evals/skia` | 25 | Active | > Want a group that is not listed here? [Open an issue](https://github.com/callstackincubator/evals/issues/new/choose) to request it. Contributions are also welcome. diff --git a/bun.lock b/bun.lock index e5b8180f..e06fa463 100644 --- a/bun.lock +++ b/bun.lock @@ -8,7 +8,7 @@ "@types/bun": "^1.3.8", "ai": "^6.0.78", "ai-sdk-provider-opencode-sdk": "^1.0.0", - "react-native": "^0.84.0", + "react-native": "0.85.3", "typescript": "^5.9.3", "yaml": "^2.8.2", "zod": "^3.23.8", @@ -22,7 +22,7 @@ "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.5.1", "eslint-plugin-simple-import-sort": "^12.1.1", - "expo": "^54.0.33", + "expo": "^56", "globals": "^15.14.0", "lefthook": "^2.1.9", "prettier": "^3.8.1", @@ -32,6 +32,7 @@ "name": "evals-testbench", "version": "1.0.0", "dependencies": { + "@expo/ui": "~56.0.17", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -41,11 +42,29 @@ "@react-navigation/native-stack": "^7.3.0", "@shopify/flash-list": "^2.3.0", "@tanstack/react-query": "^5.90.21", - "expo": "~54.0.33", - "expo-status-bar": "~3.0.9", + "expo": "^56", + "expo-audio": "~56.0.12", + "expo-build-properties": "~56.0.18", + "expo-calendar": "~56.0.8", + "expo-camera": "~56.0.8", + "expo-constants": "~56.0.18", + "expo-contacts": "~56.0.9", + "expo-file-system": "~56.0.8", + "expo-glass-effect": "~56.0.4", + "expo-image": "~56.0.11", + "expo-image-picker": "~56.0.17", + "expo-location": "~56.0.17", + "expo-media-library": "~56.0.7", + "expo-navigation-bar": "~56.0.3", + "expo-notifications": "~56.0.17", + "expo-router": "~56.2.10", + "expo-status-bar": "~56.0.4", + "expo-task-manager": "~56.0.18", + "expo-updates": "~56.0.19", + "expo-video": "~56.1.3", "jotai": "^2.18.0", - "react": "19.1.0", - "react-native": "0.81.5", + "react": "19.2.3", + "react-native": "0.85.3", "react-native-gesture-handler": "~2.28.0", "react-native-keyboard-controller": "^1.20.7", "react-native-reanimated": "~4.1.1", @@ -55,14 +74,14 @@ }, "devDependencies": { "@react-native-harness/platform-web": "^1.0.0-alpha.25", - "@types/react": "~19.1.0", + "@types/react": "~19.2.0", "react-native-harness": "^1.0.0-alpha.25", "typescript": "~5.9.2", }, }, }, "packages": { - "@0no-co/graphql.web": ["@0no-co/graphql.web@1.2.0", "", { "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" }, "optionalPeers": ["graphql"] }, "sha512-/1iHy9TTr63gE1YcR5idjx8UREz1s0kFhydf3bBLCXyqjhkIc6igAzTOx3zPifCwFR87tsh/4Pa9cNts6d2otw=="], + "@adobe/css-tools": ["@adobe/css-tools@4.5.0", "", {}, "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q=="], "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.39", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.14", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SeCZBAdDNbWpVUXiYgOAqis22p5MEYfrjRw0hiBa5hM+7sDGYQpMinUjkM8kbPXMkY+AhKLrHleBl+SuqpzlgA=="], @@ -70,7 +89,7 @@ "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.14", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7bzKd9lgiDeXM7O4U4nQ8iTxguAOkg8LZGD9AfDVZYjO5cKYRwBPwVjboFcVrxncRHu0tYxZtXZtiLKpG4pEng=="], - "@babel/code-frame": ["@babel/code-frame@7.10.4", "", { "dependencies": { "@babel/highlight": "^7.10.4" } }, "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], @@ -116,8 +135,6 @@ "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], - "@babel/highlight": ["@babel/highlight@7.25.9", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" } }, "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw=="], - "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], "@babel/plugin-proposal-decorators": ["@babel/plugin-proposal-decorators@7.29.0", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-syntax-decorators": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA=="], @@ -174,13 +191,11 @@ "@babel/plugin-transform-block-scoping": ["@babel/plugin-transform-block-scoping@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw=="], - "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], + "@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw=="], "@babel/plugin-transform-class-static-block": ["@babel/plugin-transform-class-static-block@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.12.0" } }, "sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ=="], - "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="], - - "@babel/plugin-transform-computed-properties": ["@babel/plugin-transform-computed-properties@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/template": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ=="], + "@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-replace-supers": "^7.28.6", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q=="], "@babel/plugin-transform-destructuring": ["@babel/plugin-transform-destructuring@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw=="], @@ -190,25 +205,19 @@ "@babel/plugin-transform-for-of": ["@babel/plugin-transform-for-of@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw=="], - "@babel/plugin-transform-function-name": ["@babel/plugin-transform-function-name@7.27.1", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ=="], - - "@babel/plugin-transform-literals": ["@babel/plugin-transform-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA=="], - "@babel/plugin-transform-logical-assignment-operators": ["@babel/plugin-transform-logical-assignment-operators@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A=="], "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.28.6", "", { "dependencies": { "@babel/helper-module-transforms": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA=="], "@babel/plugin-transform-named-capturing-groups-regex": ["@babel/plugin-transform-named-capturing-groups-regex@7.29.0", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.28.5", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ=="], - "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="], - - "@babel/plugin-transform-numeric-separator": ["@babel/plugin-transform-numeric-separator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w=="], + "@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg=="], "@babel/plugin-transform-object-rest-spread": ["@babel/plugin-transform-object-rest-spread@7.28.6", "", { "dependencies": { "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/plugin-transform-destructuring": "^7.28.5", "@babel/plugin-transform-parameters": "^7.27.7", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA=="], "@babel/plugin-transform-optional-catch-binding": ["@babel/plugin-transform-optional-catch-binding@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ=="], - "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="], + "@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w=="], "@babel/plugin-transform-parameters": ["@babel/plugin-transform-parameters@7.27.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg=="], @@ -222,30 +231,18 @@ "@babel/plugin-transform-react-jsx-development": ["@babel/plugin-transform-react-jsx-development@7.27.1", "", { "dependencies": { "@babel/plugin-transform-react-jsx": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q=="], - "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], - - "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], - "@babel/plugin-transform-react-pure-annotations": ["@babel/plugin-transform-react-pure-annotations@7.27.1", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA=="], - "@babel/plugin-transform-regenerator": ["@babel/plugin-transform-regenerator@7.29.0", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog=="], - "@babel/plugin-transform-runtime": ["@babel/plugin-transform-runtime@7.29.0", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "babel-plugin-polyfill-corejs2": "^0.4.14", "babel-plugin-polyfill-corejs3": "^0.13.0", "babel-plugin-polyfill-regenerator": "^0.6.5", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jlaRT5dJtMaMCV6fAuLbsQMSwz/QkvaHOHOSXRitGGwSpR1blCY4KUKoyP2tYO8vJcqYe8cEj96cqSztv3uF9w=="], "@babel/plugin-transform-shorthand-properties": ["@babel/plugin-transform-shorthand-properties@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ=="], - "@babel/plugin-transform-spread": ["@babel/plugin-transform-spread@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA=="], - - "@babel/plugin-transform-sticky-regex": ["@babel/plugin-transform-sticky-regex@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g=="], - "@babel/plugin-transform-template-literals": ["@babel/plugin-transform-template-literals@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg=="], "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw=="], "@babel/plugin-transform-unicode-regex": ["@babel/plugin-transform-unicode-regex@7.27.1", "", { "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw=="], - "@babel/preset-react": ["@babel/preset-react@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-transform-react-display-name": "^7.28.0", "@babel/plugin-transform-react-jsx": "^7.27.1", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ=="], - "@babel/preset-typescript": ["@babel/preset-typescript@7.28.5", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.28.5" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g=="], "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], @@ -254,8 +251,6 @@ "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], - "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], - "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], "@bcoe/v8-coverage": ["@bcoe/v8-coverage@0.2.3", "", {}, "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="], @@ -290,53 +285,73 @@ "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], - "@expo/cli": ["@expo/cli@54.0.23", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.8", "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devcert": "^1.2.1", "@expo/env": "~2.0.8", "@expo/image-utils": "^0.8.8", "@expo/json-file": "^10.0.8", "@expo/metro": "~54.2.0", "@expo/metro-config": "~54.0.14", "@expo/osascript": "^2.3.8", "@expo/package-manager": "^1.9.10", "@expo/plist": "^0.4.8", "@expo/prebuild-config": "^54.0.8", "@expo/schema-utils": "^0.1.8", "@expo/spawn-async": "^1.7.2", "@expo/ws-tunnel": "^1.0.1", "@expo/xcpretty": "^4.3.0", "@react-native/dev-middleware": "0.81.5", "@urql/core": "^5.0.6", "@urql/exchange-retry": "^1.3.0", "accepts": "^1.3.8", "arg": "^5.0.2", "better-opn": "~3.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "env-editor": "^0.4.1", "expo-server": "^1.0.5", "freeport-async": "^2.0.0", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.1.6", "minimatch": "^9.0.0", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^3.0.1", "pretty-bytes": "^5.6.0", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "qrcode-terminal": "0.11.0", "require-from-string": "^2.0.2", "requireg": "^0.2.2", "resolve": "^1.22.2", "resolve-from": "^5.0.0", "resolve.exports": "^2.0.3", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "source-map-support": "~0.5.21", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "tar": "^7.5.2", "terminal-link": "^2.1.1", "undici": "^6.18.2", "wrap-ansi": "^7.0.0", "ws": "^8.12.1" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "build/bin/cli" } }, "sha512-km0h72SFfQCmVycH/JtPFTVy69w6Lx1cHNDmfLfQqgKFYeeHTjx7LVDP4POHCtNxFP2UeRazrygJhlh4zz498g=="], + "@expo-google-fonts/material-symbols": ["@expo-google-fonts/material-symbols@0.4.38", "", {}, "sha512-IJkBtN1o8u9BW5fvSii1MyHPQ7Q0HxbWcVBvOrOzgMLpVtZw7R2w94wBTVR7kZwv3w1JNTESMmLA5Sqn1+Z36A=="], + + "@expo/cli": ["@expo/cli@56.1.15", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.8", "@expo/devcert": "^1.2.1", "@expo/env": "~2.3.0", "@expo/image-utils": "^0.10.1", "@expo/inline-modules": "^0.0.11", "@expo/json-file": "^10.2.0", "@expo/log-box": "^56.0.13", "@expo/metro": "~56.0.0", "@expo/metro-config": "~56.0.14", "@expo/metro-file-map": "^56.0.3", "@expo/osascript": "^2.6.0", "@expo/package-manager": "^1.12.1", "@expo/plist": "^0.7.0", "@expo/prebuild-config": "^56.0.15", "@expo/require-utils": "^56.1.3", "@expo/router-server": "^56.0.13", "@expo/schema-utils": "^56.0.0", "@expo/spawn-async": "^1.8.0", "@expo/ws-tunnel": "^2.0.0", "@expo/xcpretty": "^4.4.4", "@react-native/dev-middleware": "0.85.3", "accepts": "^1.3.8", "arg": "^5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.4", "expo-server": "^56.0.5", "fetch-nodeshim": "^0.4.10", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.1", "multitars": "^1.0.0", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.4", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "main.js" } }, "sha512-ik6++YzURB2d/mSEfYwbuNa19uOWZwVHy9THCQ/pPr6mzplKl4w9I4nlYF9lx7oluNC3NvxsSZ8/rgpVKEOJTA=="], "@expo/code-signing-certificates": ["@expo/code-signing-certificates@0.0.6", "", { "dependencies": { "node-forge": "^1.3.3" } }, "sha512-iNe0puxwBNEcuua9gmTGzq+SuMDa0iATai1FlFTMHJ/vUmKvN/V//drXoLJkVb5i5H3iE/n/qIJxyoBnXouD0w=="], - "@expo/config": ["@expo/config@12.0.13", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "@expo/config-plugins": "~54.0.4", "@expo/config-types": "^54.0.10", "@expo/json-file": "^10.0.8", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4", "sucrase": "~3.35.1" } }, "sha512-Cu52arBa4vSaupIWsF0h7F/Cg//N374nYb7HAxV0I4KceKA7x2UXpYaHOL7EEYYvp7tZdThBjvGpVmr8ScIvaQ=="], + "@expo/config": ["@expo/config@56.0.9", "", { "dependencies": { "@expo/config-plugins": "~56.0.8", "@expo/config-types": "^56.0.5", "@expo/json-file": "^10.2.0", "@expo/require-utils": "^56.1.3", "deepmerge": "^4.3.1", "getenv": "^2.0.0", "glob": "^13.0.0", "resolve-workspace-root": "^2.0.0", "semver": "^7.6.0", "slugify": "^1.3.4" } }, "sha512-/lqFeWGSrhpKJVP8tTN8LjuoIe8u8q2w7FzBL0C+wHgl+WM8l1qUIEYWy/sMvsG/NbpUIUsDHJRhQvOkU58eIw=="], - "@expo/config-plugins": ["@expo/config-plugins@54.0.4", "", { "dependencies": { "@expo/config-types": "^54.0.10", "@expo/json-file": "~10.0.8", "@expo/plist": "^0.4.8", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "resolve-from": "^5.0.0", "semver": "^7.5.4", "slash": "^3.0.0", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-g2yXGICdoOw5i3LkQSDxl2Q5AlQCrG7oniu0pCPPO+UxGb7He4AFqSvPSy8HpRUj55io17hT62FTjYRD+d6j3Q=="], + "@expo/config-plugins": ["@expo/config-plugins@56.0.8", "", { "dependencies": { "@expo/config-types": "^56.0.5", "@expo/json-file": "~10.2.0", "@expo/plist": "^0.7.0", "@expo/require-utils": "^56.1.3", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "semver": "^7.5.4", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-phTuyBhgVLfqUHMjQkAfRtbyoY6yTxoKja1awtpVnEkoJDxPJuXx1KX5uvq1eZtt4bJQ08OBJ6P95INqRSHpRg=="], - "@expo/config-types": ["@expo/config-types@54.0.10", "", {}, "sha512-/J16SC2an1LdtCZ67xhSkGXpALYUVUNyZws7v+PVsFZxClYehDSoKLqyRaGkpHlYrCc08bS0RF5E0JV6g50psA=="], + "@expo/config-types": ["@expo/config-types@56.0.5", "", {}, "sha512-GsAHO/MwW9ZRdgnmyfRXqVGLCP/zejD6rWnp5OROp8mBGRObKm4HfrjlUyT1skjMwCj1OrURx9ZfIc6yeBAkIA=="], "@expo/devcert": ["@expo/devcert@1.2.1", "", { "dependencies": { "@expo/sudo-prompt": "^9.3.1", "debug": "^3.1.0" } }, "sha512-qC4eaxmKMTmJC2ahwyui6ud8f3W60Ss7pMkpBq40Hu3zyiAaugPXnZ24145U7K36qO9UHdZUVxsCvIpz2RYYCA=="], - "@expo/devtools": ["@expo/devtools@0.1.8", "", { "dependencies": { "chalk": "^4.1.2" }, "peerDependencies": { "react": "*", "react-native": "*" }, "optionalPeers": ["react", "react-native"] }, "sha512-SVLxbuanDjJPgc0sy3EfXUMLb/tXzp6XIHkhtPVmTWJAp+FOr6+5SeiCfJrCzZFet0Ifyke2vX3sFcKwEvCXwQ=="], + "@expo/devtools": ["@expo/devtools@56.0.2", "", { "dependencies": { "chalk": "^4.1.2" }, "peerDependencies": { "react": "*", "react-native": "*" }, "optionalPeers": ["react", "react-native"] }, "sha512-ANl4kPdbe0/HQYWkDEN79S6bQhI+i/ZCnPxuC853pPsB4svhINC7Ku9lmGOKPsUUWWnrHg1spkDGQBZ4sD6JxQ=="], + + "@expo/dom-webview": ["@expo/dom-webview@56.0.5", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-UIEJxkLg6cHqofKrpWpkn9E6ApxVRtCgZhZkARPr9VV7rBVloJgeroTHs31YgU/JpbI5lLQOnfOlGo54W6C2Ew=="], - "@expo/env": ["@expo/env@2.0.8", "", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0" } }, "sha512-5VQD6GT8HIMRaSaB5JFtOXuvfDVU80YtZIuUT/GDhUF782usIXY13Tn3IdDz1Tm/lqA9qnRZQ1BF4t7LlvdJPA=="], + "@expo/env": ["@expo/env@2.3.0", "", { "dependencies": { "chalk": "^4.0.0", "debug": "^4.3.4", "getenv": "^2.0.0" } }, "sha512-9HnnIbzwTTdbwSjNLXTk0fPm9ZwMJ7c1/31tsni8HZ8Q62KzYCyspahH+V365vg5J6lr001DzNwBxVWSaYCQLg=="], - "@expo/fingerprint": ["@expo/fingerprint@0.15.4", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "minimatch": "^9.0.0", "p-limit": "^3.1.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-eYlxcrGdR2/j2M6pEDXo9zU9KXXF1vhP+V+Tl+lyY+bU8lnzrN6c637mz6Ye3em2ANy8hhUR03Raf8VsT9Ogng=="], + "@expo/expo-modules-macros-plugin": ["@expo/expo-modules-macros-plugin@0.2.2", "", {}, "sha512-4IMzPDIo/VOXREQjsJtliSfqYVZvfzU2SLFS/9sKMWF848S8CHx+e/E+Vf0TcMvpWCCKX5umyqxb13KJJ+YUzg=="], - "@expo/image-utils": ["@expo/image-utils@0.8.8", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "resolve-from": "^5.0.0", "resolve-global": "^1.0.0", "semver": "^7.6.0", "temp-dir": "~2.0.0", "unique-string": "~2.0.0" } }, "sha512-HHHaG4J4nKjTtVa1GG9PCh763xlETScfEyNxxOvfTRr8IKPJckjTyqSLEtdJoFNJ1vqiABEjW7tqGhqGibZLeA=="], + "@expo/fingerprint": ["@expo/fingerprint@0.19.4", "", { "dependencies": { "@expo/env": "^2.3.0", "@expo/spawn-async": "^1.8.0", "arg": "^5.0.2", "chalk": "^4.1.2", "debug": "^4.3.4", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "minimatch": "^10.2.2", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "bin": { "fingerprint": "bin/cli.js" } }, "sha512-PsowRlO8+S7JlO8go7yhNEXp7sqlsWDE2AlCwoss7zH0dcajXFo74Fy0KdXEc4UXK7kKoHD37oDgsZ8aHSLr7A=="], - "@expo/json-file": ["@expo/json-file@10.0.8", "", { "dependencies": { "@babel/code-frame": "~7.10.4", "json5": "^2.2.3" } }, "sha512-9LOTh1PgKizD1VXfGQ88LtDH0lRwq9lsTb4aichWTWSWqy3Ugfkhfm3BhzBIkJJfQQ5iJu3m/BoRlEIjoCGcnQ=="], + "@expo/image-utils": ["@expo/image-utils@0.10.1", "", { "dependencies": { "@expo/require-utils": "^56.1.3", "@expo/spawn-async": "^1.8.0", "chalk": "^4.0.0", "getenv": "^2.0.0", "jimp-compact": "0.16.1", "parse-png": "^2.1.0", "semver": "^7.6.0" } }, "sha512-YDeefvmYdihS7Wp3ESDUVnOgOSWmj2Cczm9lVNDdm4MqQLdAKm/LPYg83HtFQPfefRlAxyHrQR/O9kIXN9C1Wg=="], - "@expo/metro": ["@expo/metro@54.2.0", "", { "dependencies": { "metro": "0.83.3", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-config": "0.83.3", "metro-core": "0.83.3", "metro-file-map": "0.83.3", "metro-minify-terser": "0.83.3", "metro-resolver": "0.83.3", "metro-runtime": "0.83.3", "metro-source-map": "0.83.3", "metro-symbolicate": "0.83.3", "metro-transform-plugins": "0.83.3", "metro-transform-worker": "0.83.3" } }, "sha512-h68TNZPGsk6swMmLm9nRSnE2UXm48rWwgcbtAHVMikXvbxdS41NDHHeqg1rcQ9AbznDRp6SQVC2MVpDnsRKU1w=="], + "@expo/inline-modules": ["@expo/inline-modules@0.0.11", "", { "dependencies": { "@expo/config-plugins": "~56.0.8" } }, "sha512-ZlIfKL61DPnW8YUTdMEjMA31xrDDV6p7Xi8rWYyhd5qXBV8MwGwjuJ7vKeaVaMjRqxJk1N9lv7zlfyvQpRCNNw=="], - "@expo/metro-config": ["@expo/metro-config@54.0.14", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~12.0.13", "@expo/env": "~2.0.8", "@expo/json-file": "~10.0.8", "@expo/metro": "~54.2.0", "@expo/spawn-async": "^1.7.2", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "dotenv": "~16.4.5", "dotenv-expand": "~11.0.6", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.29.1", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "minimatch": "^9.0.0", "postcss": "~8.4.32", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-hxpLyDfOR4L23tJ9W1IbJJsG7k4lv2sotohBm/kTYyiG+pe1SYCAWsRmgk+H42o/wWf/HQjE5k45S5TomGLxNA=="], + "@expo/json-file": ["@expo/json-file@10.2.0", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "json5": "^2.2.3" } }, "sha512-S6XzKe3R9GQeHiUPXc3xJjOv2VJhOEwFYf7xdC2z2cUqt3kZJ9mSO877sNQloVdnW/SUCtPY3bexlM7nwq+CAQ=="], - "@expo/osascript": ["@expo/osascript@2.3.8", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "exec-async": "^2.2.0" } }, "sha512-/TuOZvSG7Nn0I8c+FcEaoHeBO07yu6vwDgk7rZVvAXoeAK5rkA09jRyjYsZo+0tMEFaToBeywA6pj50Mb3ny9w=="], + "@expo/local-build-cache-provider": ["@expo/local-build-cache-provider@56.0.8", "", { "dependencies": { "@expo/config": "~56.0.9", "chalk": "^4.1.2" } }, "sha512-UsuXwpNi57MNhzZ3be4XThc8xW6nzk3Wu37s1+2qcfZGeJcMLKDFfwO6n8YXeIiGlCsOi0Ee1rsTdgjrKt/YJQ=="], - "@expo/package-manager": ["@expo/package-manager@1.9.10", "", { "dependencies": { "@expo/json-file": "^10.0.8", "@expo/spawn-async": "^1.7.2", "chalk": "^4.0.0", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "resolve-workspace-root": "^2.0.0" } }, "sha512-axJm+NOj3jVxep49va/+L3KkF3YW/dkV+RwzqUJedZrv4LeTqOG4rhrCaCPXHTvLqCTDKu6j0Xyd28N7mnxsGA=="], + "@expo/log-box": ["@expo/log-box@56.0.13", "", { "dependencies": { "@expo/dom-webview": "^56.0.5", "anser": "^1.4.9", "stacktrace-parser": "^0.1.10" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-QWRZSpWPyjkDLVQio4R7oAzg/Av2MOt/DciFkfjr8qQ3qxGVn1Rt1oHP/80hvcWDcHFV7N6PqpyxRXw6nbxzKQ=="], - "@expo/plist": ["@expo/plist@0.4.8", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.2.3", "xmlbuilder": "^15.1.1" } }, "sha512-pfNtErGGzzRwHP+5+RqswzPDKkZrx+Cli0mzjQaus1ZWFsog5ibL+nVT3NcporW51o8ggnt7x813vtRbPiyOrQ=="], + "@expo/metro": ["@expo/metro@56.0.0", "", { "dependencies": { "metro": "0.84.4", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-minify-terser": "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" } }, "sha512-5gIgQHtEpjjvsjKfVtIv23a98LLRV0/y07PDShEwYSytAMlE3FSF8RHXqtHc1sUJL6dn7hnuIBpIbrLXXuVi0A=="], - "@expo/prebuild-config": ["@expo/prebuild-config@54.0.8", "", { "dependencies": { "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/config-types": "^54.0.10", "@expo/image-utils": "^0.8.8", "@expo/json-file": "^10.0.8", "@react-native/normalize-colors": "0.81.5", "debug": "^4.3.1", "resolve-from": "^5.0.0", "semver": "^7.6.0", "xml2js": "0.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-EA7N4dloty2t5Rde+HP0IEE+nkAQiu4A/+QGZGT9mFnZ5KKjPPkqSyYcRvP5bhQE10D+tvz6X0ngZpulbMdbsg=="], + "@expo/metro-config": ["@expo/metro-config@56.0.14", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", "@expo/config": "~56.0.9", "@expo/env": "~2.3.0", "@expo/json-file": "~10.2.0", "@expo/metro": "~56.0.0", "@expo/require-utils": "^56.1.3", "@expo/spawn-async": "^1.8.0", "@jridgewell/gen-mapping": "^0.3.13", "@jridgewell/remapping": "^2.3.5", "@jridgewell/sourcemap-codec": "^1.5.5", "browserslist": "^4.25.0", "chalk": "^4.1.0", "debug": "^4.3.2", "getenv": "^2.0.0", "glob": "^13.0.0", "hermes-parser": "^0.33.3", "jsc-safe-url": "^0.2.4", "lightningcss": "^1.30.1", "picomatch": "^4.0.4", "postcss": "^8.5.14", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*" }, "optionalPeers": ["expo"] }, "sha512-O3CIHruaTJhswPAf/nf3i8QQ3f2jl+mEwSea1eb3khuplabdy/wTQz+JvHN8VGUFyg7JKwUGU1QfO6T3JiSQqA=="], - "@expo/schema-utils": ["@expo/schema-utils@0.1.8", "", {}, "sha512-9I6ZqvnAvKKDiO+ZF8BpQQFYWXOJvTAL5L/227RUbWG1OVZDInFifzCBiqAZ3b67NRfeAgpgvbA7rejsqhY62A=="], + "@expo/metro-file-map": ["@expo/metro-file-map@56.0.3", "", { "dependencies": { "debug": "^4.3.4", "fb-watchman": "^2.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" } }, "sha512-5OGW3z8LgEYgMJOR7F3pC8llFLkb1fVqwAewbCl6S4Vkha8AFQMwOjT+9Wbka+V4rmpljpGqOnMhF4xZbD961w=="], + + "@expo/metro-runtime": ["@expo/metro-runtime@56.0.15", "", { "dependencies": { "@expo/log-box": "^56.0.13", "anser": "^1.4.9", "pretty-format": "^29.7.0", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-dom": "*", "react-native": "*" }, "optionalPeers": ["react-dom"] }, "sha512-WIWeVsL6kCSB57oYZdUA4MTkH7c67UFMIjdNoQzKXwxZYwBFE/xL2cGPDC3z8RWt0femzJTVxAVZUOW/hiqRzA=="], + + "@expo/osascript": ["@expo/osascript@2.6.0", "", { "dependencies": { "@expo/spawn-async": "^1.8.0" } }, "sha512-QvqDBlJXa8CS2vRORJ4wEflY1m0vVI07uSJdIRgBrLxRPBcsrXxrtU7+wXRXMqfq9zLwNP9XbvRsXF2omoDylg=="], + + "@expo/package-manager": ["@expo/package-manager@1.12.1", "", { "dependencies": { "@expo/json-file": "^10.2.0", "@expo/spawn-async": "^1.8.0", "chalk": "^4.0.0", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "resolve-workspace-root": "^2.0.0" } }, "sha512-fQLiFAcFRWF53mtuLK32SUJQ1ahhrTcBZPZPedYTiUT5ha5FF+UO6bPtCc0Y/hgj0/m3HCGBAuSHjbg2kI9oPQ=="], + + "@expo/plist": ["@expo/plist@0.7.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-vrpryU1GoqSIRNqRB2D3IjXDmzNYfiQpEF6AH/xknlD7eiYmEDt3mb26V7cLcedcPG8PY/1xWHdBXVQJfEAh6Q=="], + + "@expo/prebuild-config": ["@expo/prebuild-config@56.0.15", "", { "dependencies": { "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.8", "@expo/config-types": "^56.0.5", "@expo/image-utils": "^0.10.1", "@expo/json-file": "^10.2.0", "@react-native/normalize-colors": "0.85.3", "debug": "^4.3.1", "expo-modules-autolinking": "~56.0.15", "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, "sha512-6GC+QjdCkzp/5wjsqgfu/B2+2yf5MyZMtzf9szIPrLt9uKhzV2PdyM0vU0kvbj1YT8weHCtO7bsrzimman0sjA=="], + + "@expo/require-utils": ["@expo/require-utils@56.1.3", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "@babel/core": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8" }, "peerDependencies": { "typescript": "^5.0.0 || ^5.0.0-0 || ^6.0.0" }, "optionalPeers": ["typescript"] }, "sha512-KyLeOn/zzQSvuPpV5YhB/FPKnpQytno4luN918bGdPDssLBoS3N/0UbC3W0rJAn9kSFu+XpfR81eABRVsSdfgQ=="], + + "@expo/router-server": ["@expo/router-server@56.0.14", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "@expo/metro-runtime": "^56.0.15", "expo": "*", "expo-constants": "^56.0.18", "expo-font": "^56.0.6", "expo-router": "*", "expo-server": "^56.0.5", "react": "*", "react-dom": "*", "react-server-dom-webpack": "~19.0.1 || ~19.1.2 || ~19.2.1" }, "optionalPeers": ["@expo/metro-runtime", "expo-router", "react-dom", "react-server-dom-webpack"] }, "sha512-2UCTtZfcq1ZPgp3wk8/+sq9DvFI9UxrPr1jcEKMAF2DGAJLosnpc8GWNNg2hkjt6SHUOdFHIPxujWPYyho2y3A=="], + + "@expo/schema-utils": ["@expo/schema-utils@56.0.1", "", {}, "sha512-CZ/+mYbQmWeOnkCGlWy9K+lFxbJSMFY7+TqBZcKzBSTU5Q7IGRvn/sOG3TdNjIdLPmbA8xe7R/c3UUQ28R9i9w=="], "@expo/sdk-runtime-versions": ["@expo/sdk-runtime-versions@1.0.0", "", {}, "sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ=="], - "@expo/spawn-async": ["@expo/spawn-async@1.7.2", "", { "dependencies": { "cross-spawn": "^7.0.3" } }, "sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew=="], + "@expo/spawn-async": ["@expo/spawn-async@1.8.0", "", { "dependencies": { "cross-spawn": "^7.0.6" } }, "sha512-eb9xxd/LbuEGSdua4NumCu/McVB9EM+F/JxB9pWgnERw4HQ9XyTNH1KapG6oqLWR8TuRK2LQfzJlmNi94CVobw=="], "@expo/sudo-prompt": ["@expo/sudo-prompt@9.3.2", "", {}, "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw=="], - "@expo/vector-icons": ["@expo/vector-icons@15.1.1", "", { "peerDependencies": { "expo-font": ">=14.0.4", "react": "*", "react-native": "*" } }, "sha512-Iu2VkcoI5vygbtYngm7jb4ifxElNVXQYdDrYkT7UCEIiKLeWnQY0wf2ZhHZ+Wro6Sc5TaumpKUOqDRpLi5rkvw=="], + "@expo/ui": ["@expo/ui@56.0.17", "", { "dependencies": { "sf-symbols-typescript": "^2.1.0", "vaul": "^1.1.2" }, "peerDependencies": { "@babel/core": "*", "expo": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-reanimated": "*", "react-native-worklets": "*" }, "optionalPeers": ["@babel/core", "react-dom", "react-native-reanimated", "react-native-worklets"] }, "sha512-Jos9oGzurMDngrSWJesX3LSykPRvkUdANxtq2sPKBc6bAjadtZJCkthAYMaE3P9L5xrzbNRFo+2O76cRP0iYPw=="], - "@expo/ws-tunnel": ["@expo/ws-tunnel@1.0.6", "", {}, "sha512-nDRbLmSrJar7abvUjp3smDwH8HcbZcoOEa5jVPUv9/9CajgmWw20JNRwTuBRzWIWIkEJDkz20GoNA+tSwUqk0Q=="], + "@expo/ws-tunnel": ["@expo/ws-tunnel@2.0.0", "", { "peerDependencies": { "ws": "^8.0.0" } }, "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw=="], - "@expo/xcpretty": ["@expo/xcpretty@4.4.1", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "chalk": "^4.1.0", "js-yaml": "^4.1.0" }, "bin": { "excpretty": "build/cli.js" } }, "sha512-KZNxZvnGCtiM2aYYZ6Wz0Ix5r47dAvpNLApFtZWnSoERzAdOMzVBOPysBoM0JlF6FKWZ8GPqgn6qt3dV/8Zlpg=="], + "@expo/xcpretty": ["@expo/xcpretty@4.4.4", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "chalk": "^4.1.0", "js-yaml": "^4.1.0" }, "bin": { "excpretty": "build/cli.js" } }, "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], @@ -348,8 +363,6 @@ "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], - "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], - "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], @@ -360,17 +373,15 @@ "@jest/core": ["@jest/core@30.2.0", "", { "dependencies": { "@jest/console": "30.2.0", "@jest/pattern": "30.0.1", "@jest/reporters": "30.2.0", "@jest/test-result": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "ansi-escapes": "^4.3.2", "chalk": "^4.1.2", "ci-info": "^4.2.0", "exit-x": "^0.2.2", "graceful-fs": "^4.2.11", "jest-changed-files": "30.2.0", "jest-config": "30.2.0", "jest-haste-map": "30.2.0", "jest-message-util": "30.2.0", "jest-regex-util": "30.0.1", "jest-resolve": "30.2.0", "jest-resolve-dependencies": "30.2.0", "jest-runner": "30.2.0", "jest-runtime": "30.2.0", "jest-snapshot": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0", "jest-watcher": "30.2.0", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" }, "optionalPeers": ["node-notifier"] }, "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ=="], - "@jest/create-cache-key-function": ["@jest/create-cache-key-function@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3" } }, "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA=="], - "@jest/diff-sequences": ["@jest/diff-sequences@30.0.1", "", {}, "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw=="], - "@jest/environment": ["@jest/environment@29.7.0", "", { "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0" } }, "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw=="], + "@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], "@jest/expect": ["@jest/expect@30.2.0", "", { "dependencies": { "expect": "30.2.0", "jest-snapshot": "30.2.0" } }, "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA=="], "@jest/expect-utils": ["@jest/expect-utils@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0" } }, "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA=="], - "@jest/fake-timers": ["@jest/fake-timers@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", "jest-message-util": "^29.7.0", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ=="], + "@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], "@jest/get-type": ["@jest/get-type@30.1.0", "", {}, "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA=="], @@ -390,9 +401,9 @@ "@jest/test-sequencer": ["@jest/test-sequencer@30.2.0", "", { "dependencies": { "@jest/test-result": "30.2.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "slash": "^3.0.0" } }, "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q=="], - "@jest/transform": ["@jest/transform@29.7.0", "", { "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", "@jridgewell/trace-mapping": "^0.3.18", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", "jest-haste-map": "^29.7.0", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", "write-file-atomic": "^4.0.2" } }, "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw=="], + "@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - "@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], + "@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], @@ -426,6 +437,48 @@ "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.4", "", {}, "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ=="], + + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.9", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zuSVi7ziP7uQRqc+yGxsKJfNkdyHv3ZKDaHe0gzg4dRgws96TPKWIiz84tVHP4GEcEl8bC0mdt17NkcxaJHmaQ=="], + + "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="], + + "@radix-ui/react-context": ["@radix-ui/react-context@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg=="], + + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.12", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.9", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.11", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-slot": "1.2.5", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-l9ok83YBclEZhbjgzt76Hw733e6cvRKPNgO6GJ/IETlufXG9p+fRu2wlvpImQvR6xdJ8h7J8J2DBvsPEiEsKMw=="], + + "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="], + + "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-escape-keydown": "1.1.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-MhoruH6xEzsbvOmo4TNgMfmtvRGyDZw4MDSdf4ybMHfezjqwzv6hyd4lsMzBp8K9Sn6sGzCF62x1I7BYUECXOg=="], + + "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q=="], + + "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.9", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9Se8t+Zry+1rEOL7Y6l/4ANYU/TOtAtf8O2fKdwLltcaMcm6kOqYGbzO4tMFQ0bvzO920pRAoHpFZ4W85S3keQ=="], + + "@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="], + + "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.11", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-layout-effect": "1.1.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-UEytdjgEh2tJGgD/gZK4FUx6t1rNIlM3U0DENhSrG7I75FGm1DnaDuVUWF1pWAWUwGmn1sCJ1VGHn8LhN1aTOw=="], + + "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.6", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ=="], + + "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.5", "", { "dependencies": { "@radix-ui/react-slot": "1.2.5" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-zifXeB8Y88qCYx8PLZ5oQb32KwZub+s925mMoZsBBq9KUQqWKkREubTfs6ASjRPPBe7Jt9O8OHH89+95VG+grA=="], + + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.9", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-FvgPt1bRmg8Xt2QpF7NUZW3dE0ZQHGm41dAdgT2J2GJPoIXz+9Em3NobAxf4fupcxhgHu03E5CRiU2MWvObXyg=="], + + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.5", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rCMO3QsIVKv5JTY5CVbo2MvO77SpEqqYc8AvRE7OWqRDOIqAKjsp+DrmnY9uc8NPdxB5E2z47HTYGeE2+NTptg=="], + + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.5", "@radix-ui/react-roving-focus": "1.1.12", "@radix-ui/react-use-controllable-state": "1.2.3" }, "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" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-D5jwp9JNuwDeCw3CYD2Fz+sSHo0droQjC8u75dJHe4aWr5q6yBiXZU+hurXnKudRgEpUkD5TsI6bjHPo5ThUxA=="], + + "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="], + + "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.3", "", { "dependencies": { "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA=="], + + "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.3", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA=="], + + "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.2", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw=="], + + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="], + "@react-native-async-storage/async-storage": ["@react-native-async-storage/async-storage@2.2.0", "", { "dependencies": { "merge-options": "^3.0.4" }, "peerDependencies": { "react-native": "^0.0.0-0 || >=0.65 <1.0" } }, "sha512-gvRvjR5JAaUZF8tv2Kcq/Gbt3JHwbKFYfmb445rhOj6NUMx3qPLixmDx5pZAyb9at1bYvJ4/eTUipU5aki45xw=="], "@react-native-community/netinfo": ["@react-native-community/netinfo@12.0.1", "", { "peerDependencies": { "react": "*", "react-native": ">=0.59" } }, "sha512-P/3caXIvfYSJG8AWJVefukg+ZGRPs+M4Lp3pNJtgcTYoJxCjWrKQGNnCkj/Cz//zWa/avGed0i/wzm0T8vV2IQ=="], @@ -452,29 +505,29 @@ "@react-native-harness/tools": ["@react-native-harness/tools@1.0.0-alpha.25", "", { "dependencies": { "@clack/prompts": "1.0.0-alpha.9", "is-unicode-supported": "^0.1.0", "nano-spawn": "^1.0.2", "picocolors": "^1.1.1", "tslib": "^2.3.0" }, "peerDependencies": { "react-native": "*" } }, "sha512-yCULnrZB5xQitcfEI9GWNZt/i9Ffa1gKZEWMbnQwKXDVMSfOo5HjLcDQ/neGJzupWUknEtVmdXgrp7hel7jbzg=="], - "@react-native/assets-registry": ["@react-native/assets-registry@0.84.0", "", {}, "sha512-YiU9h1IN0pvvZsHbd03MaD7mE2q+ySaKMlE9tWK+3iiwtbEaMQOsMUuSJ1er2LU6ERMWfhfvCYgWpKRGOMeN8A=="], + "@react-native-masked-view/masked-view": ["@react-native-masked-view/masked-view@0.3.2", "", { "peerDependencies": { "react": ">=16", "react-native": ">=0.57" } }, "sha512-XwuQoW7/GEgWRMovOQtX3A4PrXhyaZm0lVUiY8qJDvdngjLms9Cpdck6SmGAUNqQwcj2EadHC1HwL0bEyoa/SQ=="], - "@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.81.5", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@react-native/codegen": "0.81.5" } }, "sha512-oF71cIH6je3fSLi6VPjjC3Sgyyn57JLHXs+mHWc9MoCiJJcM4nqsS5J38zv1XQ8d3zOW2JtHro+LF0tagj2bfQ=="], + "@react-native/assets-registry": ["@react-native/assets-registry@0.85.3", "", {}, "sha512-u9ZiYP23vA2IFtdFQFmetzSmk6SM0xgKIoiOsr1hXNHjHaLhOm+/Ph1ud57wX6+Dbwdzx8coJgnzSKL3W21PCg=="], - "@react-native/babel-preset": ["@react-native/babel-preset@0.81.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-arrow-functions": "^7.24.7", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-computed-properties": "^7.24.7", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-numeric-separator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.25.2", "@babel/plugin-transform-react-jsx-self": "^7.24.7", "@babel/plugin-transform-react-jsx-source": "^7.24.7", "@babel/plugin-transform-regenerator": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-shorthand-properties": "^7.24.7", "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", "@react-native/babel-plugin-codegen": "0.81.5", "babel-plugin-syntax-hermes-parser": "0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" } }, "sha512-UoI/x/5tCmi+pZ3c1+Ypr1DaRMDLI3y+Q70pVLLVgrnC3DHsHRIbHcCHIeG/IJvoeFqFM2sTdhSOLJrf8lOPrA=="], + "@react-native/babel-plugin-codegen": ["@react-native/babel-plugin-codegen@0.85.3", "", { "dependencies": { "@babel/traverse": "^7.29.0", "@react-native/codegen": "0.85.3" } }, "sha512-Wc94zGfeFG8Njf9SHMPfYZP04kjigkOps6F1TYTvd7ZVXuGxqseCDgxc50LWcOhOCLypI9n3oVVqz81C3p44ZA=="], - "@react-native/codegen": ["@react-native/codegen@0.84.0", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "tinyglobby": "^0.2.15", "yargs": "^17.6.2" } }, "sha512-TcTAO58JigCw9onYTrbE2yK2js5YNgqbmnpYyq9oXz2mofbX7JcK53kIi7fhqyJhie8RkY+X85zSOTWNs6S3CA=="], + "@react-native/codegen": ["@react-native/codegen@0.85.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.29.0", "hermes-parser": "0.33.3", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "tinyglobby": "^0.2.15", "yargs": "^17.6.2" } }, "sha512-/JkS1lGLyzBWP1FbgDwaqEf7qShIC6pUC1M0a/YMAd/v4iqR24MRkQWe7jkYvcBQ2LpEhs5NGE9InhxSv21zCA=="], - "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.84.0", "", { "dependencies": { "@react-native/dev-middleware": "0.84.0", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.3", "metro-config": "^0.83.3", "metro-core": "^0.83.3", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-uYoLBHnAzod4E5dA5rPPQeny2A5RD0PiIJQ4r+2F7cvA+5bZ8+znxw4TdaSiEk8uhN+clffI4d2bl9V4+xEK+Q=="], + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.85.3", "", { "dependencies": { "@react-native/dev-middleware": "0.85.3", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.84.3", "metro-config": "^0.84.3", "metro-core": "^0.84.3", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "0.85.3" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-fs85dmbIqNmtzEixDb0g+q6R3Vt4H9eAt8/inIZdDKfjN76+sUJA2r1nxODQ76bU23MrIbz8sI7KFBPaWk/zQw=="], - "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.5", "", {}, "sha512-bnd9FSdWKx2ncklOetCgrlwqSGhMHP2zOxObJbOWXoj7GHEmih4MKarBo5/a8gX8EfA1EwRATdfNBQ81DY+h+w=="], + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.85.3", "", {}, "sha512-uAu7rM5o/Np1zgp6fi5zM1sP1aB8DcS7DdOLcj/TkSutOAjkMqqd2lWt1/+3S7qXexRHVK5XcP+o3VXo4L/V0A=="], - "@react-native/debugger-shell": ["@react-native/debugger-shell@0.84.0", "", { "dependencies": { "cross-spawn": "^7.0.6", "debug": "^4.4.0", "fb-dotslash": "0.5.8" } }, "sha512-5t/NvQLYk/d0kWlGOMNobkjfimqBc+/LYRmSOkgKm+pyOhxjygCLSnRjAUkeRALSZ8h6MKGTz1Wc4pbmJr7T0Q=="], + "@react-native/debugger-shell": ["@react-native/debugger-shell@0.85.3", "", { "dependencies": { "cross-spawn": "^7.0.6", "debug": "^4.4.0", "fb-dotslash": "0.5.8" } }, "sha512-/jRAaT9boiCttIcEwS02WPwYkUihqsjSaK/TMtHz05vT6uMgac9PaQt5kzBQLIABv5aEIa5gtrMmKVz49MjkjQ=="], - "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.5", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.5", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-WfPfZzboYgo/TUtysuD5xyANzzfka8Ebni6RIb2wDxhb56ERi7qDrE4xGhtPsjCL4pQBXSVxyIlCy0d8I6EgGA=="], + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.85.3", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.85.3", "@react-native/debugger-shell": "0.85.3", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.3.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^7.5.10" } }, "sha512-JYzBiT4A8w+KQt+dOD5v+ti+tDrGoPnsSTuApq3Ls4RB5sfWbDlYMyz3dbc8qBIHz9tv0sQ5+eOu6Xwqzr5AQA=="], - "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.84.0", "", {}, "sha512-j8g/I4Z+SAdh2NXOVng4rmfYgPoeJBZwAKoGPpSe/wB/9XDLh9IRGUTg8dGS5BWUy2471xBUoGZPwHb6QMJmVw=="], + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.85.3", "", {}, "sha512-39dY2j50Q1pntejzwt3XL7vwXtrj8jcIfHq6E+gyu3jzYxZJVvMkMutQ39vSg6zinIQOX36oQDhidXUbCXzgoA=="], - "@react-native/js-polyfills": ["@react-native/js-polyfills@0.84.0", "", {}, "sha512-xaxmzYWLgHH+2uAZQ0owEkDE58hOTWmuBKD/Gl+cDFD3mFfSK4lZpin/3hiXtE5LB4BwgqICsPN07zCAqx6Fpg=="], + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.85.3", "", {}, "sha512-U2+aMshIXf1uFn77tpBb/xhHWB9vkVrMpt7kkucAugF8hJKYTDGB587X7WwelHduK2KBfhl4giSv0rzZGoef9A=="], - "@react-native/normalize-colors": ["@react-native/normalize-colors@0.84.0", "", {}, "sha512-7JgZyWtQ9Sz4qZvCTsURUtuv8/niEZ/iCorp7eExc3GgpBWNazPumieiUoWPdgRKofU0Bqpr2/dJevEn2hrlwA=="], + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.85.3", "", {}, "sha512-hj0PScZEhIbcOvQV5yMKX3ha4XEIOy/SVE1Rrpp0beW0dpNLOgSC7KDxGewmDnIHK9YdQUXGY9eMEfShUMIaZw=="], - "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.84.0", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-ugwSj0Gb4MYrcm8uQrQw8qHPx5RKGDLuZRAP/AuwneFizHx8YCLBEFbOYRGWgxHBRtkJ70D1o+jpIx3CK3p5lw=="], + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.85.3", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.2.0", "react": "*", "react-native": "0.85.3" }, "optionalPeers": ["@types/react"] }, "sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig=="], "@react-navigation/bottom-tabs": ["@react-navigation/bottom-tabs@7.14.0", "", { "dependencies": { "@react-navigation/elements": "^2.9.5", "color": "^4.2.3", "sf-symbols-typescript": "^2.1.0" }, "peerDependencies": { "@react-navigation/native": "^7.1.28", "react": ">= 18.2.0", "react-native": "*", "react-native-safe-area-context": ">= 4.0.0", "react-native-screens": ">= 4.0.0" } }, "sha512-oG2VdoInuIyK0o9o90Yo47hTCS+sPyVE7k8eSB37vt3pq3uQxjh8V3xJpsQfOfNlRUXOPB/ejH93nSBlP7ZHmQ=="], @@ -498,7 +551,7 @@ "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], - "@sinonjs/fake-timers": ["@sinonjs/fake-timers@10.3.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA=="], + "@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], @@ -506,8 +559,16 @@ "@tanstack/react-query": ["@tanstack/react-query@5.90.21", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg=="], + "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], + + "@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="], + + "@testing-library/user-event": ["@testing-library/user-event@14.6.1", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw=="], + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], + "@types/aria-query": ["@types/aria-query@5.0.4", "", {}, "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw=="], + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], @@ -522,12 +583,12 @@ "@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="], + "@types/emscripten": ["@types/emscripten@1.41.5", "", {}, "sha512-cMQm7pxu6BxtHyqJ7mQZ2kXWV5SLmugybFdHCBbJ5eHzOo6VhBckEgAT3//rP5FwPHNPeEiq4SmQ5ucBwsOo4Q=="], + "@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="], "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], - "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="], - "@types/hammerjs": ["@types/hammerjs@2.0.46", "", {}, "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw=="], "@types/istanbul-lib-coverage": ["@types/istanbul-lib-coverage@2.0.6", "", {}, "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w=="], @@ -542,7 +603,7 @@ "@types/node": ["@types/node@25.2.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ=="], - "@types/react": ["@types/react@19.1.17", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA=="], + "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="], "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], @@ -610,10 +671,6 @@ "@unrs/resolver-binding-win32-x64-msvc": ["@unrs/resolver-binding-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g=="], - "@urql/core": ["@urql/core@5.2.0", "", { "dependencies": { "@0no-co/graphql.web": "^1.0.13", "wonka": "^6.3.2" } }, "sha512-/n0ieD0mvvDnVAXEQgX/7qJiVcvYvNkOHeBvkwtylfjydar123caCXcl58PXFY11oU1oquJocVXHxLAbtv4x1A=="], - - "@urql/exchange-retry": ["@urql/exchange-retry@1.3.2", "", { "dependencies": { "@urql/core": "^5.1.2", "wonka": "^6.3.2" } }, "sha512-TQMCz2pFJMfpNxmSfX1VSfTjwUIFx/mL+p1bnfM1xjjdla7Z+KnGMW/EhFbpckp3LyWAH4PgOsMwOMnIN+MBFg=="], - "@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], "@vitest/expect": ["@vitest/expect@4.0.16", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.0.16", "@vitest/utils": "4.0.16", "chai": "^6.2.1", "tinyrainbow": "^3.0.3" } }, "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA=="], @@ -650,14 +707,16 @@ "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], - "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + "arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="], "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + + "aria-query": ["aria-query@5.3.2", "", {}, "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw=="], + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], @@ -682,15 +741,13 @@ "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - "async-limiter": ["async-limiter@1.0.1", "", {}, "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="], - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - "babel-jest": ["babel-jest@29.7.0", "", { "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg=="], + "babel-jest": ["babel-jest@30.2.0", "", { "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw=="], - "babel-plugin-istanbul": ["babel-plugin-istanbul@6.1.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" } }, "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA=="], + "babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@29.6.3", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg=="], + "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "^7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="], "babel-plugin-polyfill-corejs2": ["babel-plugin-polyfill-corejs2@0.4.15", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-define-polyfill-provider": "^0.6.6", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw=="], @@ -702,24 +759,26 @@ "babel-plugin-react-native-web": ["babel-plugin-react-native-web@0.21.2", "", {}, "sha512-SPD0J6qjJn8231i0HZhlAGH6NORe+QvRSQM2mwQEzJ2Fb3E4ruWTiiicPlHjmeWShDXLcvoorOCXjeR7k/lyWA=="], - "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.32.0", "", { "dependencies": { "hermes-parser": "0.32.0" } }, "sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg=="], + "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.33.3", "", { "dependencies": { "hermes-parser": "0.33.3" } }, "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA=="], "babel-plugin-transform-flow-enums": ["babel-plugin-transform-flow-enums@0.0.2", "", { "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" } }, "sha512-g4aaCrDDOsWjbm0PUUeVnkcVd6AKJsVc/MbnPhEotEpkeJQP6b8nzewohQi7+QS8UyPehOhGWn0nOwjvWpmMvQ=="], "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], - "babel-preset-expo": ["babel-preset-expo@54.0.10", "", { "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/preset-react": "^7.22.15", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-preset": "0.81.5", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.29.1", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4", "resolve-from": "^5.0.0" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo"] }, "sha512-wTt7POavLFypLcPW/uC5v8y+mtQKDJiyGLzYCjqr9tx0Qc3vCXcDKk1iCFIj/++Iy5CWhhTflEa7VvVPNWeCfw=="], + "babel-preset-expo": ["babel-preset-expo@56.0.15", "", { "dependencies": { "@babel/generator": "^7.20.5", "@babel/helper-module-imports": "^7.25.9", "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-proposal-export-default-from": "^7.24.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-default-from": "^7.24.7", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-transform-async-generator-functions": "^7.25.4", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.25.4", "@babel/plugin-transform-class-static-block": "^7.27.1", "@babel/plugin-transform-classes": "^7.25.4", "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-export-namespace-from": "^7.25.9", "@babel/plugin-transform-flow-strip-types": "^7.25.2", "@babel/plugin-transform-for-of": "^7.24.7", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-modules-commonjs": "^7.24.8", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-react-display-name": "^7.24.7", "@babel/plugin-transform-react-jsx": "^7.28.6", "@babel/plugin-transform-react-jsx-development": "^7.27.1", "@babel/plugin-transform-react-pure-annotations": "^7.27.1", "@babel/plugin-transform-runtime": "^7.24.7", "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/preset-typescript": "^7.23.0", "@react-native/babel-plugin-codegen": "0.85.3", "babel-plugin-react-compiler": "^1.0.0", "babel-plugin-react-native-web": "~0.21.0", "babel-plugin-syntax-hermes-parser": "^0.33.3", "babel-plugin-transform-flow-enums": "^0.0.2", "debug": "^4.3.4" }, "peerDependencies": { "@babel/runtime": "^7.20.0", "expo": "*", "expo-widgets": "^56.0.18", "react-refresh": ">=0.14.0 <1.0.0" }, "optionalPeers": ["@babel/runtime", "expo", "expo-widgets"] }, "sha512-0MqbQoM6nBUbKvgu2xJ4VixZnUTGTq3HB2WwvOikdO4CiPxbQ+wGA25fOoHHSni5iEFW39wy6y1ookTWlq3wVw=="], + + "babel-preset-jest": ["babel-preset-jest@30.2.0", "", { "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ=="], - "babel-preset-jest": ["babel-preset-jest@29.6.3", "", { "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA=="], + "badgin": ["badgin@1.2.3", "", {}, "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw=="], "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "barcode-detector": ["barcode-detector@3.2.0", "", { "dependencies": { "zxing-wasm": "3.1.0" } }, "sha512-MrT5TT058ptG5YB157pHLfXKVpp0BKEfQBOb8QvzTbatzmLDu85JJ0Gd/sCYwbwdwStJvxsYflrSN6D6E4Ndyw=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], - "better-opn": ["better-opn@3.0.2", "", { "dependencies": { "open": "^8.0.4" } }, "sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ=="], - "big-integer": ["big-integer@1.6.52", "", {}, "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg=="], "birpc": ["birpc@2.9.0", "", {}, "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw=="], @@ -736,8 +795,6 @@ "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], - "buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], - "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], @@ -762,11 +819,9 @@ "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], - "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], - "chrome-launcher": ["chrome-launcher@0.15.2", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0" }, "bin": { "print-chrome-path": "bin/print-chrome-path.js" } }, "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ=="], - "chromium-edge-launcher": ["chromium-edge-launcher@0.2.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg=="], + "chromium-edge-launcher": ["chromium-edge-launcher@0.3.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^1.0.0", "mkdirp": "^1.0.4" } }, "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA=="], "ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="], @@ -776,6 +831,8 @@ "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], "clone": ["clone@1.0.4", "", {}, "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg=="], @@ -808,7 +865,7 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "crypto-random-string": ["crypto-random-string@2.0.0", "", {}, "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="], + "css.escape": ["css.escape@1.5.1", "", {}, "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="], "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], @@ -824,8 +881,6 @@ "dedent": ["dedent@1.7.1", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg=="], - "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], - "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], "deepmerge": ["deepmerge@4.3.1", "", {}, "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="], @@ -834,25 +889,27 @@ "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], - "define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], - "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], "detect-newline": ["detect-newline@3.1.0", "", {}, "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="], + "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="], + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], - "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + "dnssd-advertise": ["dnssd-advertise@1.1.6", "", {}, "sha512-Ndrrf6BMPalkQPd/zubL+4YghH2J9NspapQ09uDXwYbvOPkP0oaqf5CkcwJ0b50kS2O3ul6yVu+jz+RY62Cejg=="], - "dotenv": ["dotenv@16.4.7", "", {}, "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="], + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], - "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], + "dom-accessibility-api": ["dom-accessibility-api@0.6.3", "", {}, "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -868,8 +925,6 @@ "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], - "env-editor": ["env-editor@0.4.2", "", {}, "sha512-ObFo8v4rQJAE59M69QzwloxPZtd33TpYEIjtKD1rrFDcM1Gd7IkDxEBU+HriziN6HSHQnBJi8Dmy+JWkav5HKA=="], - "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], @@ -944,33 +999,83 @@ "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], - "exec-async": ["exec-async@2.2.0", "", {}, "sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw=="], - "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], "exit-x": ["exit-x@0.2.2", "", {}, "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ=="], "expect": ["expect@30.2.0", "", { "dependencies": { "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw=="], - "expo": ["expo@54.0.33", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "54.0.23", "@expo/config": "~12.0.13", "@expo/config-plugins": "~54.0.4", "@expo/devtools": "0.1.8", "@expo/fingerprint": "0.15.4", "@expo/metro": "~54.2.0", "@expo/metro-config": "54.0.14", "@expo/vector-icons": "^15.0.3", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~54.0.10", "expo-asset": "~12.0.12", "expo-constants": "~18.0.13", "expo-file-system": "~19.0.21", "expo-font": "~14.0.11", "expo-keep-awake": "~15.0.8", "expo-modules-autolinking": "3.0.24", "expo-modules-core": "3.0.29", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-without-unicode": "8.0.0-3" }, "peerDependencies": { "@expo/dom-webview": "*", "@expo/metro-runtime": "*", "react": "*", "react-native": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/dom-webview", "@expo/metro-runtime", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-3yOEfAKqo+gqHcV8vKcnq0uA5zxlohnhA3fu4G43likN8ct5ZZ3LjAh9wDdKteEkoad3tFPvwxmXW711S5OHUw=="], + "expo": ["expo@56.0.11", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "^56.1.15", "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.8", "@expo/devtools": "~56.0.2", "@expo/dom-webview": "~56.0.5", "@expo/fingerprint": "^0.19.4", "@expo/local-build-cache-provider": "^56.0.8", "@expo/log-box": "^56.0.13", "@expo/metro": "~56.0.0", "@expo/metro-config": "~56.0.14", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~56.0.15", "expo-asset": "~56.0.17", "expo-constants": "~56.0.18", "expo-file-system": "~56.0.8", "expo-font": "~56.0.6", "expo-keep-awake": "~56.0.3", "expo-modules-autolinking": "~56.0.15", "expo-modules-core": "~56.0.16", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" }, "peerDependencies": { "@expo/metro-runtime": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-web": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/metro-runtime", "react-dom", "react-native-web", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-YqF+q+JqfobDU5yFym3h1vQqzbl7rFiDB4wAJEyK6NK+KLeyf4pfzydQcNTyqLXQKcQBG1reBJExfDShoAYTzw=="], + + "expo-application": ["expo-application@56.0.3", "", { "peerDependencies": { "expo": "*" } }, "sha512-DdGGPlMuM6cSTeKhbvh6OeLr2O/+EI5BHKYrD+Do8sJPYgLwzGrgESELfyjJCpEhFzT+TgKIdmLmWXhNUQnHiw=="], + + "expo-asset": ["expo-asset@56.0.17", "", { "dependencies": { "@expo/image-utils": "^0.10.1", "expo-constants": "~56.0.18" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-GFN5j+8SPkyv0nfsiFHewmdB/D0tL237TsBE/gSfFOFy/J3a52py7IulcSqkA3sQE/u/UlD5BmvP5ssS4//nUg=="], + + "expo-audio": ["expo-audio@56.0.12", "", { "peerDependencies": { "expo": "*", "expo-asset": "*", "react": "*", "react-native": "*" } }, "sha512-ne2UIO/HsQoBL9e+tGs5N9Sf3NyW5sJMm4sDkexbSJRc2IchLDG+9Msu/+l5N4RlZ8SiF42wRyWsh/Usg+SwOw=="], + + "expo-build-properties": ["expo-build-properties@56.0.18", "", { "dependencies": { "@expo/schema-utils": "^56.0.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-at03ytur1Vfyl9ddtRMqIdSyR/oV57GM04+NZ5rhFTF0mC7dmKzxS9RBb34KHDPdT8UwUt7KsKbzYD1lnxLAKg=="], + + "expo-calendar": ["expo-calendar@56.0.8", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-gxH+J+teP3CBXPybQHuwzTYrFEmSz4irh2n2KSVzzbIRqjVwgVH42op/BViOqxIkMlOlx3hmXNVIkB8RiMtIvg=="], + + "expo-camera": ["expo-camera@56.0.8", "", { "dependencies": { "barcode-detector": "^3.0.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-UDOpUUMisFRmCv1XQV1MJCKGAH2CsIC1Rs6P9Bbc6JLVmbxEKAd5dK68y6cScOdWURxVfJ0PRcjYnSuc8ayyIQ=="], + + "expo-constants": ["expo-constants@56.0.18", "", { "dependencies": { "@expo/env": "~2.3.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-8AMtbDGl/WVPnWlmbpGmvcdnNCy9E4PFnwdVwj600vljkMDPSxcAcjw8GVXEPk3PpZ+ngTqsrkltWyj0UKYAxw=="], + + "expo-contacts": ["expo-contacts@56.0.9", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-EFtslaAyyh0ni2GpN7Ie2A1+Nq5IxqW3s3g7piNwXkbYS1AsV33gI2rjAuA0Mryd/E82O2trVSnJqp4gHOJ41A=="], + + "expo-eas-client": ["expo-eas-client@56.0.1", "", {}, "sha512-r8h0ZIExacCrSRgY+ARfhMvFqosLHLJt1L7jyhvabfr1DN/ZDKDsYbovss2tzkpEUZGxZ3BPcB5epCwUsBBdOA=="], + + "expo-file-system": ["expo-file-system@56.0.8", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-NrH41/8snGIBSbYicwVLB4txPdgCATd7ZYhMAGS3YJZ9GbnduhlAoV4/YCbGayjrbpE9bJb/6wegPL/zmvRMnQ=="], - "expo-asset": ["expo-asset@12.0.12", "", { "dependencies": { "@expo/image-utils": "^0.8.8", "expo-constants": "~18.0.12" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-CsXFCQbx2fElSMn0lyTdRIyKlSXOal6ilLJd+yeZ6xaC7I9AICQgscY5nj0QcwgA+KYYCCEQEBndMsmj7drOWQ=="], + "expo-font": ["expo-font@56.0.6", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-D4s72Aei844C2s8Vy61qMr6wLEjv6BMrXA1oyRQ0x8LJBbpm5gyogUohc0lABUURVLCqsnBIDdztegl3hktmmg=="], - "expo-constants": ["expo-constants@18.0.13", "", { "dependencies": { "@expo/config": "~12.0.13", "@expo/env": "~2.0.8" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ=="], + "expo-glass-effect": ["expo-glass-effect@56.0.4", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-xI9rXtDwi7RW82uAlfyaXO6+k21ApWJ2tHAWYqPr/FjfmZbKsgNJ4Q0iZzGPCwboqjTGxaRZ61SZxBl8hDt5iA=="], - "expo-file-system": ["expo-file-system@19.0.21", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-s3DlrDdiscBHtab/6W1osrjGL+C2bvoInPJD7sOwmxfJ5Woynv2oc+Fz1/xVXaE/V7HE/+xrHC/H45tu6lZzzg=="], + "expo-image": ["expo-image@56.0.11", "", { "dependencies": { "sf-symbols-typescript": "^2.2.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*", "react-native-web": "*" }, "optionalPeers": ["react-native-web"] }, "sha512-k2xwxGk14xi6zxmEGAU4rUTb1lK5qf0y0Qb8+Jaggnul0KaJJxcq9qvyDp9iyJBW35cp9isONAUnNtIiooZ/Pw=="], - "expo-font": ["expo-font@14.0.11", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-ga0q61ny4s/kr4k8JX9hVH69exVSIfcIc19+qZ7gt71Mqtm7xy2c6kwsPTCyhBW2Ro5yXTT8EaZOpuRi35rHbg=="], + "expo-image-loader": ["expo-image-loader@56.0.3", "", { "peerDependencies": { "expo": "*" } }, "sha512-JgUo4fUeU1ZC+z8iBFj8v7yoGQnZrLbOVPyNE+DWVrld55F2F6R1ck+rmdm/8TNWLz1LhNQfD7c3XYP1ZikxXA=="], - "expo-keep-awake": ["expo-keep-awake@15.0.8", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-YK9M1VrnoH1vLJiQzChZgzDvVimVoriibiDIFLbQMpjYBnvyfUeHJcin/Gx1a+XgupNXy92EQJLgI/9ZuXajYQ=="], + "expo-image-picker": ["expo-image-picker@56.0.17", "", { "dependencies": { "expo-image-loader": "~56.0.3" }, "peerDependencies": { "expo": "*" } }, "sha512-/RojW1ptyQNV89hEeDdaoHCkn38+546MqakMyB0acFf0HLh5ZI7wxQCHkxr16qjuQMy11M+96GlX9Z6vgXF7Nw=="], - "expo-modules-autolinking": ["expo-modules-autolinking@3.0.24", "", { "dependencies": { "@expo/spawn-async": "^1.7.2", "chalk": "^4.1.0", "commander": "^7.2.0", "require-from-string": "^2.0.2", "resolve-from": "^5.0.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-TP+6HTwhL7orDvsz2VzauyQlXJcAWyU3ANsZ7JGL4DQu8XaZv/A41ZchbtAYLfozNA2Ya1Hzmhx65hXryBMjaQ=="], + "expo-json-utils": ["expo-json-utils@56.0.0", "", {}, "sha512-lUqyv9aIGDbYTQ5Nux2FnH2/Dz0w5uJ8Pr080eS0StXi2jr5OmuMNErpzUnpfnYOU55xKotd4AHv68PfV/ludg=="], - "expo-modules-core": ["expo-modules-core@3.0.29", "", { "dependencies": { "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-LzipcjGqk8gvkrOUf7O2mejNWugPkf3lmd9GkqL9WuNyeN2fRwU0Dn77e3ZUKI3k6sI+DNwjkq4Nu9fNN9WS7Q=="], + "expo-keep-awake": ["expo-keep-awake@56.0.3", "", { "peerDependencies": { "expo": "*", "react": "*" } }, "sha512-CLMJXtEiMKknD3Rpm8CRwE6ZJUzu2yCEmRk1sgfHAJ1zIbuEWY3dpPDubtsnuzWm+2k6Sru+yaFbYsvPWmTiBA=="], - "expo-server": ["expo-server@1.0.5", "", {}, "sha512-IGR++flYH70rhLyeXF0Phle56/k4cee87WeQ4mamS+MkVAVP+dDlOHf2nN06Z9Y2KhU0Gp1k+y61KkghF7HdhA=="], + "expo-linking": ["expo-linking@56.0.14", "", { "dependencies": { "expo-constants": "~56.0.18", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-IvVQHWC+Cj4fK5qD3iEVYqpU2a4rLW0IpAAlGJ4MH+H1fyZiHh3eN6qg2WmoclOEPfYATSuEa+dQT6wfgVpXlQ=="], - "expo-status-bar": ["expo-status-bar@3.0.9", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-xyYyVg6V1/SSOZWh4Ni3U129XHCnFHBTcUo0dhWtFDrZbNp/duw5AGsQfb2sVeU0gxWHXSY1+5F0jnKYC7WuOw=="], + "expo-location": ["expo-location@56.0.17", "", { "dependencies": { "@expo/image-utils": "^0.10.1" }, "peerDependencies": { "expo": "*" } }, "sha512-3kEONgFApqGzuRhgWyYGb/nXK+rYaeuHtcCYkuVNbrDSlHYYe+mgQPeM4Iuqv43Fihmp0mKsNtq7zX030nE+VA=="], + + "expo-manifests": ["expo-manifests@56.0.4", "", { "dependencies": { "expo-json-utils": "~56.0.0" }, "peerDependencies": { "expo": "*" } }, "sha512-Fokawl2UkiExIF0bqGoblRFA8lYpROVD+EpvDwSW4LgqQyPwNua1gLSgHZjdl5GsVugfRMMWE3LHaibDyX93hw=="], + + "expo-media-library": ["expo-media-library@56.0.7", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-lVsXsagjDYuySr+WWvc6BfRHTXttnWeVX4qMP2ls7JyAVSECQOAQpqz47uZiJsEohtpCoDTLRL2mcn/XY8fLoQ=="], + + "expo-modules-autolinking": ["expo-modules-autolinking@56.0.15", "", { "dependencies": { "@expo/require-utils": "^56.1.3", "@expo/spawn-async": "^1.8.0", "chalk": "^4.1.0", "commander": "^7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-WqpBFwLzn7DsrUkWltIjVmAjwuI1VdQ2jRMlvk1nh2kVadwdJBkSjUBQWRifsEePNhiMT/rFOovBolUU/ARt5w=="], + + "expo-modules-core": ["expo-modules-core@56.0.16", "", { "dependencies": { "@expo/expo-modules-macros-plugin": "0.2.2", "expo-modules-jsi": "~56.0.9", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": "^0.7.4 || ^0.8.0" }, "optionalPeers": ["react-native-worklets"] }, "sha512-IVdT0CnqOpQCPdemA5rb50CPbbhWeJePnvuH0yUmOmyMkNky8WVOdRQtVicoIv4CCG5hDrzPIxULD4YOHZ5CHg=="], + + "expo-modules-jsi": ["expo-modules-jsi@56.0.9", "", { "peerDependencies": { "react-native": "*" } }, "sha512-2lfDkRcsP/Qh2upS+nu0MS0tfGsghc6ehTivzbgM5nJz0MGYhAJxCJSeendWM+aOQutQAwzsoxrNT0nW8lRAwA=="], + + "expo-navigation-bar": ["expo-navigation-bar@56.0.3", "", { "dependencies": { "debug": "^4.3.2" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-7k8jyJojMs59gIsAPOFk/gCz1BTFy5S0Qf3i2uUW1f2CFoWcQSSyR4VnsmppBkzIKrBzZjcuFmdsZmYO+GZ4og=="], + + "expo-notifications": ["expo-notifications@56.0.17", "", { "dependencies": { "@expo/image-utils": "^0.10.1", "abort-controller": "^3.0.0", "badgin": "^1.1.5", "expo-application": "~56.0.3", "expo-constants": "~56.0.18" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-Yn6JUKmoBDkQeznbuUn4cHF2u44r1ErJTneW65MBFt7NLG8U8/VGQ4bBVwswm5nPH1/V92UoXPgvCssScPFRDg=="], + + "expo-router": ["expo-router@56.2.10", "", { "dependencies": { "@expo/log-box": "^56.0.13", "@expo/metro-runtime": "^56.0.15", "@expo/schema-utils": "^56.0.0", "@expo/ui": "^56.0.17", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "client-only": "^0.0.1", "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^56.0.4", "expo-server": "^56.0.5", "expo-symbols": "^56.0.6", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", "react-native-screens": "^4.25.2", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^56.0.18", "expo-linking": "^56.0.14", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-u7WcdsFAjSrQS7Bdb1VbNPE3xNcd/BZ6qXSS31UAJKhaYIb+ik3jJSy/W5kY3qKipwbwlo3CSb1WnZ2XYs7F+Q=="], + + "expo-server": ["expo-server@56.0.5", "", {}, "sha512-SmM2p2g3Jrktpiazcst+OxhjSzOHXKAY4BPURHYHXvApzzoybMmrNF4IEZ8DKZ145BhSe4ydAmlEFCRTsdtgUQ=="], + + "expo-status-bar": ["expo-status-bar@56.0.4", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-IGs/fDfkHXofy2ZQrGiXayhFK04HB85FZXorhcEhDZEcqASKgSqpak+HwUtAaR0MeTJwWyHNF7I6VmVbbp8EcA=="], + + "expo-structured-headers": ["expo-structured-headers@56.0.0", "", {}, "sha512-Yv4x+SQxNnMQm4nu8NFfzx197YaDhdYH2N0u7tGErwWTmH9Tm1SAhqo7bLbBWLC9kf7W+kdzTshLU9rTiCXWGw=="], + + "expo-symbols": ["expo-symbols@56.0.6", "", { "dependencies": { "@expo-google-fonts/material-symbols": "^0.4.1", "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "expo-font": "*", "react": "*", "react-native": "*" } }, "sha512-BrA81DjcNafdj7gXVhdrExb9LtUiSVyOf/NavyMmDAHgHMY1GqeR5cnn1PSAZeYKnSgQhee/H89XUpAxtog5hg=="], + + "expo-task-manager": ["expo-task-manager@56.0.18", "", { "dependencies": { "unimodules-app-loader": "~56.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-abTKDhlZ572wSwNuZ9HkDw6rl+kKLq0TkqheIEbGoRkMQVEGV3D5GYYY0gg84TO/HvAqiipdcBFQH8+9uHj70Q=="], + + "expo-updates": ["expo-updates@56.0.19", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/plist": "^0.7.0", "@expo/spawn-async": "^1.8.0", "arg": "^4.1.0", "chalk": "^4.1.2", "debug": "^4.3.4", "expo-eas-client": "~56.0.0", "expo-manifests": "~56.0.4", "expo-structured-headers": "~56.0.0", "expo-updates-interface": "~56.0.1", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "nullthrows": "^1.1.1", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*", "expo-dev-client": "*", "react": "*", "react-native": "*" }, "optionalPeers": ["expo-dev-client"], "bin": { "expo-updates": "bin/cli.js" } }, "sha512-tTSPYO5h8wDA6a+wQ2v/SRdnOdz29x0npGHCv+4Ev31Fz5r05Ii1Wgfh3BlTXNz8mikMReDsZCf6YN71YeQKpw=="], + + "expo-updates-interface": ["expo-updates-interface@56.0.2", "", { "peerDependencies": { "expo": "*" } }, "sha512-eWTwSZ9y8vrULG2oBn2TQSSIwBGSq/TxGJ3jY6tuVS2FWH/ASRIiKs3zkUZTRoC3ZuV2alz0mUClYV7nNrFx8g=="], + + "expo-video": ["expo-video@56.1.3", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-Ht2BMdx11RnGKxILL/P4t/hl4kqWXq1vLaoOrLZlDed+IXgf8hdDI9jmtEEgsIHwf3jaHFXblJCRVuS9mIxKAw=="], "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], @@ -992,6 +1097,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fetch-nodeshim": ["fetch-nodeshim@0.4.10", "", {}, "sha512-m6I8ALe4L4XpdETy7MJZWs6L1IVMbjs99bwbpIKphxX+0CTns4IKDWJY0LWfr4YsFjfg+z1TjzTMU8lKl8rG0w=="], + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], @@ -1014,8 +1121,6 @@ "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], - "freeport-async": ["freeport-async@2.0.0", "", {}, "sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ=="], - "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], @@ -1036,6 +1141,8 @@ "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], + "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], @@ -1048,12 +1155,10 @@ "getenv": ["getenv@2.0.0", "", {}, "sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ=="], - "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], - "global-dirs": ["global-dirs@0.1.1", "", { "dependencies": { "ini": "^1.3.4" } }, "sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg=="], - "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], @@ -1080,11 +1185,11 @@ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], - "hermes-compiler": ["hermes-compiler@250829098.0.7", "", {}, "sha512-8QOmg1VjAWv8poFVslJDY8qkvjTy/UiO3R/hyGoC0IAchLzBdS9/TmAvI9cN1F3yLTEjimAIQQtUslpBMPXVVg=="], + "hermes-compiler": ["hermes-compiler@250829098.0.10", "", {}, "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w=="], - "hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="], + "hermes-estree": ["hermes-estree@0.33.3", "", {}, "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg=="], - "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="], + "hermes-parser": ["hermes-parser@0.33.3", "", { "dependencies": { "hermes-estree": "0.33.3" } }, "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA=="], "hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "^16.7.0" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="], @@ -1098,8 +1203,6 @@ "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], - "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], - "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], @@ -1110,12 +1213,12 @@ "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], - "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.2", "side-channel": "^1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], @@ -1194,7 +1297,7 @@ "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.2", "", {}, "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg=="], - "istanbul-lib-instrument": ["istanbul-lib-instrument@5.2.1", "", { "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.2.0", "semver": "^6.3.0" } }, "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg=="], + "istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], "istanbul-lib-report": ["istanbul-lib-report@3.0.1", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", "supports-color": "^7.1.0" } }, "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw=="], @@ -1220,11 +1323,11 @@ "jest-each": ["jest-each@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "chalk": "^4.1.2", "jest-util": "30.2.0", "pretty-format": "30.2.0" } }, "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ=="], - "jest-environment-node": ["jest-environment-node@29.7.0", "", { "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", "@types/node": "*", "jest-mock": "^29.7.0", "jest-util": "^29.7.0" } }, "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw=="], + "jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], "jest-get-type": ["jest-get-type@29.6.3", "", {}, "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw=="], - "jest-haste-map": ["jest-haste-map@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", "jest-regex-util": "^29.6.3", "jest-util": "^29.7.0", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA=="], + "jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], "jest-leak-detector": ["jest-leak-detector@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "pretty-format": "30.2.0" } }, "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ=="], @@ -1232,11 +1335,11 @@ "jest-message-util": ["jest-message-util@30.2.0", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@jest/types": "30.2.0", "@types/stack-utils": "^2.0.3", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "micromatch": "^4.0.8", "pretty-format": "30.2.0", "slash": "^3.0.0", "stack-utils": "^2.0.6" } }, "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw=="], - "jest-mock": ["jest-mock@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "jest-util": "^29.7.0" } }, "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw=="], + "jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], "jest-pnp-resolver": ["jest-pnp-resolver@1.2.3", "", { "peerDependencies": { "jest-resolve": "*" }, "optionalPeers": ["jest-resolve"] }, "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w=="], - "jest-regex-util": ["jest-regex-util@29.6.3", "", {}, "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg=="], + "jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], "jest-resolve": ["jest-resolve@30.2.0", "", { "dependencies": { "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-pnp-resolver": "^1.2.3", "jest-util": "30.2.0", "jest-validate": "30.2.0", "slash": "^3.0.0", "unrs-resolver": "^1.7.11" } }, "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A=="], @@ -1248,7 +1351,7 @@ "jest-snapshot": ["jest-snapshot@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@babel/generator": "^7.27.5", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-syntax-typescript": "^7.27.1", "@babel/types": "^7.27.3", "@jest/expect-utils": "30.2.0", "@jest/get-type": "30.1.0", "@jest/snapshot-utils": "30.2.0", "@jest/transform": "30.2.0", "@jest/types": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0", "chalk": "^4.1.2", "expect": "30.2.0", "graceful-fs": "^4.2.11", "jest-diff": "30.2.0", "jest-matcher-utils": "30.2.0", "jest-message-util": "30.2.0", "jest-util": "30.2.0", "pretty-format": "30.2.0", "semver": "^7.7.2", "synckit": "^0.11.8" } }, "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA=="], - "jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="], + "jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], "jest-validate": ["jest-validate@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", "jest-get-type": "^29.6.3", "leven": "^3.1.0", "pretty-format": "^29.7.0" } }, "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw=="], @@ -1286,7 +1389,7 @@ "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], - "lan-network": ["lan-network@0.1.7", "", { "bin": { "lan-network": "dist/lan-network-cli.js" } }, "sha512-mnIlAEMu4OyEvUNdzco9xpuB9YVcPkQec+QsgycBCtPZvEqWPCDPfbAE4OJMdBBWpZWtpCn1xw9jJYlwjWI5zQ=="], + "lan-network": ["lan-network@0.2.1", "", { "bin": { "lan-network": "dist/lan-network-cli.js" } }, "sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A=="], "lefthook": ["lefthook@2.1.9", "", { "optionalDependencies": { "lefthook-darwin-arm64": "2.1.9", "lefthook-darwin-x64": "2.1.9", "lefthook-freebsd-arm64": "2.1.9", "lefthook-freebsd-x64": "2.1.9", "lefthook-linux-arm64": "2.1.9", "lefthook-linux-x64": "2.1.9", "lefthook-openbsd-arm64": "2.1.9", "lefthook-openbsd-x64": "2.1.9", "lefthook-windows-arm64": "2.1.9", "lefthook-windows-x64": "2.1.9" }, "bin": { "lefthook": "bin/index.js" } }, "sha512-bwDaIOViTktE8kJLf9jP0p+H2/RDTlFFlc43Am2YgUsX22hI6Sq4RbzsrecwzY5y+MHTipOH7WsmWSEniePHWQ=="], @@ -1356,6 +1459,8 @@ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lz-string": ["lz-string@1.5.0", "", { "bin": { "lz-string": "bin/bin.js" } }, "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ=="], + "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], @@ -1372,33 +1477,33 @@ "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], - "metro": ["metro@0.83.3", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.32.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-config": "0.83.3", "metro-core": "0.83.3", "metro-file-map": "0.83.3", "metro-resolver": "0.83.3", "metro-runtime": "0.83.3", "metro-source-map": "0.83.3", "metro-symbolicate": "0.83.3", "metro-transform-plugins": "0.83.3", "metro-transform-worker": "0.83.3", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q=="], + "metro": ["metro@0.84.4", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "accepts": "^2.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.35.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-config": "0.84.4", "metro-core": "0.84.4", "metro-file-map": "0.84.4", "metro-resolver": "0.84.4", "metro-runtime": "0.84.4", "metro-source-map": "0.84.4", "metro-symbolicate": "0.84.4", "metro-transform-plugins": "0.84.4", "metro-transform-worker": "0.84.4", "mime-types": "^3.0.1", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA=="], - "metro-babel-transformer": ["metro-babel-transformer@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" } }, "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g=="], + "metro-babel-transformer": ["metro-babel-transformer@0.84.4", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.35.0", "metro-cache-key": "0.84.4", "nullthrows": "^1.1.1" } }, "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g=="], - "metro-cache": ["metro-cache@0.83.3", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.3" } }, "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q=="], + "metro-cache": ["metro-cache@0.84.4", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.84.4" } }, "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg=="], - "metro-cache-key": ["metro-cache-key@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw=="], + "metro-cache-key": ["metro-cache-key@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw=="], - "metro-config": ["metro-config@0.83.3", "", { "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.3", "metro-cache": "0.83.3", "metro-core": "0.83.3", "metro-runtime": "0.83.3", "yaml": "^2.6.1" } }, "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA=="], + "metro-config": ["metro-config@0.84.4", "", { "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.84.4", "metro-cache": "0.84.4", "metro-core": "0.84.4", "metro-runtime": "0.84.4", "yaml": "^2.6.1" } }, "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q=="], - "metro-core": ["metro-core@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.3" } }, "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw=="], + "metro-core": ["metro-core@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.84.4" } }, "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ=="], - "metro-file-map": ["metro-file-map@0.83.3", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA=="], + "metro-file-map": ["metro-file-map@0.84.4", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ=="], - "metro-minify-terser": ["metro-minify-terser@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ=="], + "metro-minify-terser": ["metro-minify-terser@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ=="], - "metro-resolver": ["metro-resolver@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ=="], + "metro-resolver": ["metro-resolver@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A=="], - "metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], + "metro-runtime": ["metro-runtime@0.84.4", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q=="], - "metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], + "metro-source-map": ["metro-source-map@0.84.4", "", { "dependencies": { "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.84.4", "nullthrows": "^1.1.1", "ob1": "0.84.4", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g=="], - "metro-symbolicate": ["metro-symbolicate@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw=="], + "metro-symbolicate": ["metro-symbolicate@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.84.4", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA=="], - "metro-transform-plugins": ["metro-transform-plugins@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A=="], + "metro-transform-plugins": ["metro-transform-plugins@0.84.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow=="], - "metro-transform-worker": ["metro-transform-worker@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.3", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-minify-terser": "0.83.3", "metro-source-map": "0.83.3", "metro-transform-plugins": "0.83.3", "nullthrows": "^1.1.1" } }, "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA=="], + "metro-transform-worker": ["metro-transform-worker@0.84.4", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.29.1", "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "flow-enums-runtime": "^0.0.6", "metro": "0.84.4", "metro-babel-transformer": "0.84.4", "metro-cache": "0.84.4", "metro-cache-key": "0.84.4", "metro-minify-terser": "0.84.4", "metro-source-map": "0.84.4", "metro-transform-plugins": "0.84.4", "nullthrows": "^1.1.1" } }, "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], @@ -1410,19 +1515,19 @@ "mimic-fn": ["mimic-fn@1.2.0", "", {}, "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="], + "min-indent": ["min-indent@1.0.1", "", {}, "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="], + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], - "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], - "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + "multitars": ["multitars@1.0.0", "", {}, "sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg=="], "nano-spawn": ["nano-spawn@1.0.3", "", {}, "sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA=="], @@ -1434,8 +1539,6 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "nested-error-stacks": ["nested-error-stacks@2.0.1", "", {}, "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A=="], - "nocache": ["nocache@4.0.0", "", {}, "sha512-AntnTbmKZvNYIsTVPPwv7dfZdAfo/6H/2ZlZACK66NAOQtIApxkB/6pf/c+s+ACW8vemGJzUCyVTssrzNUK6yQ=="], "node-forge": ["node-forge@1.3.3", "", {}, "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg=="], @@ -1452,7 +1555,7 @@ "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], - "ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], + "ob1": ["ob1@0.84.4", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -1486,7 +1589,7 @@ "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + "p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="], "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], @@ -1516,7 +1619,7 @@ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], - "picomatch": ["picomatch@3.0.1", "", {}, "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag=="], + "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], @@ -1534,7 +1637,7 @@ "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], + "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], @@ -1542,8 +1645,6 @@ "prettier-linter-helpers": ["prettier-linter-helpers@1.0.1", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg=="], - "pretty-bytes": ["pretty-bytes@5.6.0", "", {}, "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="], - "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], "proc-log": ["proc-log@4.2.0", "", {}, "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA=="], @@ -1560,8 +1661,6 @@ "pure-rand": ["pure-rand@7.0.1", "", {}, "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ=="], - "qrcode-terminal": ["qrcode-terminal@0.11.0", "", { "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ=="], - "query-string": ["query-string@7.1.3", "", { "dependencies": { "decode-uri-component": "^0.2.2", "filter-obj": "^1.1.0", "split-on-first": "^1.0.0", "strict-uri-encode": "^2.0.0" } }, "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg=="], "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], @@ -1570,17 +1669,19 @@ "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], - "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - - "react": ["react@19.1.0", "", {}, "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg=="], + "react": ["react@19.2.3", "", {}, "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA=="], "react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="], + "react-dom": ["react-dom@19.2.7", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.7" } }, "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ=="], + + "react-fast-compare": ["react-fast-compare@3.2.2", "", {}, "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="], + "react-freeze": ["react-freeze@1.0.4", "", { "peerDependencies": { "react": ">=17.0.0" } }, "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA=="], - "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="], - "react-native": ["react-native@0.84.0", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.84.0", "@react-native/codegen": "0.84.0", "@react-native/community-cli-plugin": "0.84.0", "@react-native/gradle-plugin": "0.84.0", "@react-native/js-polyfills": "0.84.0", "@react-native/normalize-colors": "0.84.0", "@react-native/virtualized-lists": "0.84.0", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "hermes-compiler": "250829098.0.7", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.3", "metro-source-map": "^0.83.3", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "tinyglobby": "^0.2.15", "whatwg-fetch": "^3.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "^19.2.3" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-CcBfucLDHz8MAjQx9kFXasYtpcn8zP1YapUgGtAy0psRZTLShwF9yeh5+ErSgEK2gXV1CCSz7hqCZqx1eMyBLA=="], + "react-native": ["react-native@0.85.3", "", { "dependencies": { "@react-native/assets-registry": "0.85.3", "@react-native/codegen": "0.85.3", "@react-native/community-cli-plugin": "0.85.3", "@react-native/gradle-plugin": "0.85.3", "@react-native/js-polyfills": "0.85.3", "@react-native/normalize-colors": "0.85.3", "@react-native/virtualized-lists": "0.85.3", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-plugin-syntax-hermes-parser": "0.33.3", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "hermes-compiler": "250829098.0.10", "invariant": "^2.2.4", "memoize-one": "^5.0.0", "metro-runtime": "^0.84.3", "metro-source-map": "^0.84.3", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.27.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "tinyglobby": "^0.2.15", "whatwg-fetch": "^3.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "peerDependencies": { "@react-native/jest-preset": "0.85.3", "@types/react": "^19.1.1", "react": "^19.2.3" }, "optionalPeers": ["@react-native/jest-preset", "@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-HN/fGC+3nZVcDNcw7gfbM/DuqZAvI9Mz+/SxuhODaua4JY0BPzhfTzWXRyTR4mRgMHmShTPpH2PYMTxvZrsdZA=="], "react-native-drawer-layout": ["react-native-drawer-layout@4.2.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*", "react-native-gesture-handler": ">= 2.0.0", "react-native-reanimated": ">= 2.0.0" } }, "sha512-UG/PTTeyyr43KahbgoGyXri8LMO5USHY3/RUpeKBKwCc7xLVGnDLOVNSRrJw0dDc7YmPbmAyJ4oxp8nKboKKuw=="], @@ -1602,6 +1703,14 @@ "react-refresh": ["react-refresh@0.14.2", "", {}, "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA=="], + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], + + "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + + "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], + + "redent": ["redent@3.0.0", "", { "dependencies": { "indent-string": "^4.0.0", "strip-indent": "^3.0.0" } }, "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg=="], + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], "regenerate": ["regenerate@1.4.2", "", {}, "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="], @@ -1620,30 +1729,20 @@ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], - - "requireg": ["requireg@0.2.2", "", { "dependencies": { "nested-error-stacks": "~2.0.1", "rc": "~1.2.7", "resolve": "~1.7.1" } }, "sha512-nYzyjnFcPNGR3lx9lwPPPnuQxv6JWEZd2Ci0u9opN7N5zUEPIhY/GbL3vMGOr2UXwEg9WwSyV9X9Y/kLFgPsOg=="], - "resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], "resolve-cwd": ["resolve-cwd@3.0.0", "", { "dependencies": { "resolve-from": "^5.0.0" } }, "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "resolve-global": ["resolve-global@1.0.0", "", { "dependencies": { "global-dirs": "^0.1.1" } }, "sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw=="], - "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], "resolve-workspace-root": ["resolve-workspace-root@2.0.1", "", {}, "sha512-nR23LHAvaI6aHtMg6RWoaHpdR4D881Nydkzi2CixINyg9T00KgaJdJI6Vwty+Ps8WLxZHuxsS0BseWjxSA4C+w=="], - "resolve.exports": ["resolve.exports@2.0.3", "", {}, "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A=="], - "restore-cursor": ["restore-cursor@2.0.0", "", { "dependencies": { "onetime": "^2.0.0", "signal-exit": "^3.0.2" } }, "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q=="], "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], @@ -1666,6 +1765,8 @@ "serve-static": ["serve-static@1.16.3", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "~0.19.1" } }, "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA=="], + "server-only": ["server-only@0.0.1", "", {}, "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA=="], + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", "has-property-descriptors": "^1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], @@ -1676,6 +1777,8 @@ "sf-symbols-typescript": ["sf-symbols-typescript@2.2.0", "", {}, "sha512-TPbeg0b7ylrswdGCji8FRGFAKuqbpQlLbL8SOle3j1iHSs5Ob5mhvMAxWN2UItOjgALAB5Zp3fmMfj8mbWvXKw=="], + "shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], @@ -1722,6 +1825,8 @@ "stacktrace-parser": ["stacktrace-parser@0.1.11", "", { "dependencies": { "type-fest": "^0.7.1" } }, "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg=="], + "standard-navigation": ["standard-navigation@0.0.5", "", {}, "sha512-YAmzwAiiQVocZxO/VGPFiQHcu5pKiz09QIGC0MK6aRMoa3E0QkoTQgcqJr7ZZ3OMiNhu4DkaGElFI5htjOIDbw=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], @@ -1754,12 +1859,12 @@ "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + "strip-indent": ["strip-indent@3.0.0", "", { "dependencies": { "min-indent": "^1.0.0" } }, "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ=="], + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], "structured-headers": ["structured-headers@0.4.1", "", {}, "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg=="], - "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], - "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], "supports-hyperlinks": ["supports-hyperlinks@2.3.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA=="], @@ -1768,9 +1873,7 @@ "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], - "tar": ["tar@7.5.9", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg=="], - - "temp-dir": ["temp-dir@2.0.0", "", {}, "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg=="], + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], "terminal-link": ["terminal-link@2.1.1", "", { "dependencies": { "ansi-escapes": "^4.2.1", "supports-hyperlinks": "^2.0.0" } }, "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ=="], @@ -1778,10 +1881,6 @@ "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], - "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], - - "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "throat": ["throat@5.0.0", "", {}, "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], @@ -1794,9 +1893,9 @@ "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], - "ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="], + "toqr": ["toqr@0.1.1", "", {}, "sha512-FWAPzCIHZHnrE/5/w9MPk0kK25hSQSH2IKhYh9PyjS3SG/+IEMvlwIHbhz+oF7xl54I+ueZlVnMjyzdSwLmAwA=="], - "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + "ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": ">=4.2.0" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="], "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], @@ -1820,8 +1919,6 @@ "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici": ["undici@6.23.0", "", {}, "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g=="], - "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unicode-canonical-property-names-ecmascript": ["unicode-canonical-property-names-ecmascript@2.0.1", "", {}, "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg=="], @@ -1832,7 +1929,7 @@ "unicode-property-aliases-ecmascript": ["unicode-property-aliases-ecmascript@2.2.0", "", {}, "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ=="], - "unique-string": ["unique-string@2.0.0", "", { "dependencies": { "crypto-random-string": "^2.0.0" } }, "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg=="], + "unimodules-app-loader": ["unimodules-app-loader@56.0.1", "", {}, "sha512-Z801jeBOQMUF/ExklxT1BqhEV/oF2/Bii7PFYAj/8Sauxl7oKvZbf70peRzzAU0mG7UQ3yU/UO/EpD1JyJ2WcA=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], @@ -1842,8 +1939,12 @@ "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="], + "use-latest-callback": ["use-latest-callback@0.2.6", "", { "peerDependencies": { "react": ">=16.8" } }, "sha512-FvRG9i1HSo0wagmX63Vrm8SnlUU3LMM3WyZkQ76RnslpBrX694AdG4A0zQBx2B3ZifFA0yv/BaEHGBnEax5rZg=="], + "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], "utils-merge": ["utils-merge@1.0.1", "", {}, "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="], @@ -1856,6 +1957,8 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "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" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], + "vlq": ["vlq@1.0.1", "", {}, "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="], "walker": ["walker@1.0.8", "", { "dependencies": { "makeerror": "1.0.12" } }, "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="], @@ -1864,11 +1967,9 @@ "wcwidth": ["wcwidth@1.0.1", "", { "dependencies": { "defaults": "^1.0.3" } }, "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg=="], - "webidl-conversions": ["webidl-conversions@5.0.0", "", {}, "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="], - "whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="], - "whatwg-url-without-unicode": ["whatwg-url-without-unicode@8.0.0-3", "", { "dependencies": { "buffer": "^5.4.3", "punycode": "^2.1.1", "webidl-conversions": "^5.0.0" } }, "sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig=="], + "whatwg-url-minimum": ["whatwg-url-minimum@0.1.2", "", {}, "sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -1880,8 +1981,6 @@ "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], - "wonka": ["wonka@6.3.5", "", {}, "sha512-SSil+ecw6B4/Dm7Pf2sAshKQ5hWFvfyGlfPbEd6A14dOH6VDjrmbY86u6nZvy9omGwwIPFR8V41+of1EezgoUw=="], - "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], @@ -1890,7 +1989,7 @@ "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "write-file-atomic": ["write-file-atomic@4.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" } }, "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg=="], + "write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], "ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], @@ -1902,7 +2001,7 @@ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], - "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="], @@ -1910,13 +2009,13 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], - "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "zustand": ["zustand@5.0.11", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg=="], - "@babel/core/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "zxing-wasm": ["zxing-wasm@3.1.0", "", { "dependencies": { "@types/emscripten": "^1.41.5", "type-fest": "^5.7.0" } }, "sha512-5+3V1wPRx4gvbeLH2jB7n2cKrYJ1q4i3QgjnBUtrDPeqxJSi6BdzKJg4y6aF6bgW8zfntnYJyrkqFMevDhL2NA=="], "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -1928,47 +2027,23 @@ "@babel/helper-define-polyfill-provider/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], - "@babel/highlight/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - "@babel/plugin-transform-runtime/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "@babel/template/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "@babel/traverse/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "@babel/traverse--for-generate-function-map/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], - "@expo/cli/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], - - "@expo/cli/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@expo/cli/resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + "@expo/cli/arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], "@expo/cli/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], - "@expo/config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], - - "@expo/config-plugins/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], - "@expo/devcert/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], - "@expo/fingerprint/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], - - "@expo/fingerprint/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "@expo/metro-config/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "@expo/metro-config/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], + "@expo/fingerprint/arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], - "@expo/metro-config/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + "@expo/fingerprint/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], - "@expo/prebuild-config/@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.5", "", {}, "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g=="], - - "@expo/xcpretty/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "@expo/ws-tunnel/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], @@ -1982,83 +2057,27 @@ "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.2", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg=="], - "@jest/console/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@jest/console/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - - "@jest/core/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "@jest/core/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - "@jest/core/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - "@jest/core/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "@jest/core/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "@jest/core/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "@jest/core/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], "@jest/core/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "@jest/fake-timers/jest-message-util": ["jest-message-util@29.7.0", "", { "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w=="], - - "@jest/globals/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], - - "@jest/globals/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@jest/globals/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "@jest/pattern/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "@jest/reporters/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "@jest/reporters/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - "@jest/reporters/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "@jest/reporters/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "@jest/reporters/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "@jest/reporters/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - "@jest/snapshot-utils/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@jest/test-result/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@jest/test-sequencer/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "@react-native-harness/babel-preset/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], + "@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], "@react-native-harness/bridge/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], - "@react-native-harness/jest/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - - "@react-native-harness/jest/p-limit": ["p-limit@7.3.0", "", { "dependencies": { "yocto-queue": "^1.2.1" } }, "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw=="], - "@react-native-harness/runtime/event-target-shim": ["event-target-shim@6.0.2", "", {}, "sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA=="], - "@react-native/babel-plugin-codegen/@react-native/codegen": ["@react-native/codegen@0.81.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g=="], - - "@react-native/babel-preset/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.28.6", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.28.6", "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw=="], - - "@react-native/babel-preset/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-replace-supers": "^7.28.6", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q=="], - - "@react-native/babel-preset/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg=="], - - "@react-native/babel-preset/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.28.6", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w=="], - - "@react-native/babel-preset/babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], + "@testing-library/dom/aria-query": ["aria-query@5.3.0", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A=="], - "@react-native/codegen/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - "@react-native/community-cli-plugin/@react-native/dev-middleware": ["@react-native/dev-middleware@0.84.0", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.84.0", "@react-native/debugger-shell": "0.84.0", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^7.5.10" } }, "sha512-c0o7YW39AUI1FSLV/TFSszr87kQGmaePAQK0ygIRnwZ2fAGDnQ5Iu/tk3u9O5lVH6nTjfAwTKJ3El9YeEWDeEQ=="], - - "@react-native/dev-middleware/ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="], - - "@react-navigation/core/react-is": ["react-is@19.2.4", "", {}, "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA=="], + "@testing-library/dom/pretty-format": ["pretty-format@27.5.1", "", { "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" } }, "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ=="], "@typescript-eslint/project-service/@typescript-eslint/types": ["@typescript-eslint/types@8.55.0", "", {}, "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w=="], @@ -2074,12 +2093,6 @@ "babel-plugin-polyfill-corejs2/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "babel-plugin-syntax-hermes-parser/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], - - "babel-preset-expo/babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], - - "better-opn/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], - "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], @@ -2114,15 +2127,13 @@ "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - "evals-testbench/react-native": ["react-native@0.81.5", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.5", "@react-native/codegen": "0.81.5", "@react-native/community-cli-plugin": "0.81.5", "@react-native/gradle-plugin": "0.81.5", "@react-native/js-polyfills": "0.81.5", "@react-native/normalize-colors": "0.81.5", "@react-native/virtualized-lists": "0.81.5", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw=="], - "execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], - "expect/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], + "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], - "expect/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + "expo-router/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], - "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + "expo-router/react-native-screens": ["react-native-screens@4.25.2", "", { "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": ">=0.82.0" } }, "sha512-1Nj1fusFd+rIMKU/qC9yGKVG+3ofh11d3OdBQKL1iVvQfKvcB8vhvTGQf2TkfxW3bamxN+hCZIXmNuU0mRkyDg=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], @@ -2136,125 +2147,67 @@ "foreground-child/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], + "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "hosted-git-info/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], - "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], - - "jest-changed-files/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + "jest-changed-files/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - "jest-circus/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], - - "jest-circus/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-circus/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + "jest-circus/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "jest-circus/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-cli/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-cli/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-cli/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], - "jest-config/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-config/babel-jest": ["babel-jest@30.2.0", "", { "dependencies": { "@jest/transform": "30.2.0", "@types/babel__core": "^7.20.5", "babel-plugin-istanbul": "^7.0.1", "babel-preset-jest": "30.2.0", "chalk": "^4.1.2", "graceful-fs": "^4.2.11", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-0" } }, "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw=="], - "jest-config/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "jest-config/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "jest-config/jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], - - "jest-config/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-config/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-config/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], "jest-config/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], "jest-diff/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-each/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-each/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-each/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], + "jest-environment-node/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], + "jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + "jest-leak-detector/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], "jest-matcher-utils/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-message-util/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "jest-message-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - "jest-message-util/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-resolve/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "jest-resolve/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-resolve/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], - "jest-resolve-dependencies/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-runner/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], - - "jest-runner/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "jest-runner/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-runner/jest-environment-node": ["jest-environment-node@30.2.0", "", { "dependencies": { "@jest/environment": "30.2.0", "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0", "jest-util": "30.2.0", "jest-validate": "30.2.0" } }, "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA=="], - - "jest-runner/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "jest-runner/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-runner/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - "jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="], - - "jest-runtime/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], - - "jest-runtime/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], + "jest-runner/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], - "jest-runtime/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "jest-runtime/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="], "jest-runtime/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "jest-runtime/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "jest-runtime/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "jest-runtime/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-runtime/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-runtime/strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], - "jest-snapshot/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "jest-snapshot/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-snapshot/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - "jest-snapshot/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "jest-watcher/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "jest-validate/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], - "jest-watcher/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], + "jest-worker/jest-util": ["jest-util@29.7.0", "", { "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", "picomatch": "^2.2.3" } }, "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA=="], "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -2262,21 +2215,21 @@ "log-symbols/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - - "metro/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "metro/accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "metro/ci-info": ["ci-info@2.0.0", "", {}, "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="], - "metro/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "metro/hermes-parser": ["hermes-parser@0.35.0", "", { "dependencies": { "hermes-estree": "0.35.0" } }, "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA=="], + + "metro/mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], - "metro-babel-transformer/hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], + "metro-babel-transformer/hermes-parser": ["hermes-parser@0.35.0", "", { "dependencies": { "hermes-estree": "0.35.0" } }, "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "ora/chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], - "parse-json/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + "p-locate/p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], "parse-png/pngjs": ["pngjs@3.4.0", "", {}, "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="], @@ -2284,20 +2237,28 @@ "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], - "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "postcss/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], - "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + "pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "react-native/react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-dom/react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], "react-native-reanimated/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "react-native-worklets/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], + + "react-native-worklets/@babel/plugin-transform-classes": ["@babel/plugin-transform-classes@7.28.4", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-globals": "^7.28.0", "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1", "@babel/traverse": "^7.28.4" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA=="], + + "react-native-worklets/@babel/plugin-transform-nullish-coalescing-operator": ["@babel/plugin-transform-nullish-coalescing-operator@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA=="], + + "react-native-worklets/@babel/plugin-transform-optional-chaining": ["@babel/plugin-transform-optional-chaining@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg=="], + "react-native-worklets/@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="], "react-native-worklets/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], - "requireg/resolve": ["resolve@1.7.1", "", { "dependencies": { "path-parse": "^1.0.5" } }, "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw=="], - "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "simple-plist/bplist-parser": ["bplist-parser@0.3.1", "", { "dependencies": { "big-integer": "1.6.x" } }, "sha512-PyJxiNtA5T2PlLIeBot4lbp7rj4OadzjnMZD/G5zuBNt8ei/yCU7+wW0h2bag9vr8c+/WuRWmSxbqAl9hL1rBA=="], @@ -2314,10 +2275,10 @@ "strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], - "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], @@ -2330,29 +2291,13 @@ "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], - - "@babel/highlight/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], - - "@babel/highlight/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], - - "@babel/highlight/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], - - "@expo/cli/glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], - - "@expo/cli/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "@expo/config-plugins/glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], - - "@expo/config/glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], + "write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - "@expo/fingerprint/glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], - - "@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], - "@expo/metro-config/glob/minimatch": ["minimatch@10.2.3", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg=="], + "zxing-wasm/type-fest": ["type-fest@5.7.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg=="], - "@expo/metro-config/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "@expo/fingerprint/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], @@ -2364,86 +2309,22 @@ "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "@jest/console/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/console/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@jest/console/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@jest/core/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "@jest/core/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - - "@jest/core/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/core/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "@jest/core/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - - "@jest/core/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "@jest/core/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "@jest/fake-timers/jest-message-util/@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - - "@jest/globals/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], - - "@jest/globals/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/globals/jest-mock/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - - "@jest/reporters/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "@jest/reporters/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "@jest/reporters/@jest/transform/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "@jest/reporters/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - - "@jest/reporters/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "@jest/core/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "@jest/reporters/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@jest/reporters/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "@jest/reporters/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@jest/reporters/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "@jest/reporters/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "@jest/snapshot-utils/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/test-result/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/test-sequencer/jest-haste-map/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@jest/test-sequencer/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "@jest/test-sequencer/jest-haste-map/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "@jest/test-sequencer/jest-haste-map/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - - "@jest/test-sequencer/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + "@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "@react-native-harness/babel-preset/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "@react-native-harness/jest/jest-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "@react-native-harness/jest/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@react-native-harness/jest/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@react-native-harness/jest/p-limit/yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], - - "@react-native/codegen/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - - "@react-native/community-cli-plugin/@react-native/dev-middleware/@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.84.0", "", {}, "sha512-n7JKYVDCbA2aj8/5/OD1IK7nuiAYj5l/Z6yhGf7GG4EGaeQdthqdb0LZbseaRPyZK/7tLfdnLdqlqdTQC6/UTQ=="], + "@testing-library/dom/pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "babel-plugin-syntax-hermes-parser/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], - "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "connect/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -2472,193 +2353,73 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.55.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.55.0", "@typescript-eslint/tsconfig-utils": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw=="], - "evals-testbench/react-native/@react-native/assets-registry": ["@react-native/assets-registry@0.81.5", "", {}, "sha512-705B6x/5Kxm1RKRvSv0ADYWm5JOnoiQ1ufW7h8uu2E6G9Of/eE6hP/Ivw3U5jI16ERqZxiKQwk34VJbB0niX9w=="], - - "evals-testbench/react-native/@react-native/codegen": ["@react-native/codegen@0.81.5", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-a2TDA03Up8lpSa9sh5VRGCQDXgCTOyDOFH+aqyinxp1HChG8uk89/G+nkJ9FPd0rqgi25eCTR16TWdS3b+fA6g=="], - - "evals-testbench/react-native/@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.5", "", { "dependencies": { "@react-native/dev-middleware": "0.81.5", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-yWRlmEOtcyvSZ4+OvqPabt+NS36vg0K/WADTQLhrYrm9qdZSuXmq8PmdJWz/68wAqKQ+4KTILiq2kjRQwnyhQw=="], - - "evals-testbench/react-native/@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.5", "", {}, "sha512-hORRlNBj+ReNMLo9jme3yQ6JQf4GZpVEBLxmTXGGlIL78MAezDZr5/uq9dwElSbcGmLEgeiax6e174Fie6qPLg=="], - - "evals-testbench/react-native/@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.5", "", {}, "sha512-fB7M1CMOCIUudTRuj7kzxIBTVw2KXnsgbQ6+4cbqSxo8NmRRhA0Ul4ZUzZj3rFd3VznTL4Brmocv1oiN0bWZ8w=="], - - "evals-testbench/react-native/@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.5", "", {}, "sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g=="], - - "evals-testbench/react-native/@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.5", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-UVXgV/db25OPIvwZySeToXD/9sKKhOdkcWmmf4Jh8iBZuyfML+/5CasaZ1E7Lqg6g3uqVQq75NqIwkYmORJMPw=="], - - "evals-testbench/react-native/babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], - - "evals-testbench/react-native/scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], - - "evals-testbench/react-native/ws": ["ws@6.2.3", "", { "dependencies": { "async-limiter": "~1.0.0" } }, "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA=="], - "execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], - "expect/jest-mock/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "expect/jest-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "expect/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "expect/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "jest-changed-files/jest-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], - "jest-changed-files/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "jest-changed-files/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "jest-changed-files/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "jest-circus/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], - - "jest-circus/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "jest-circus/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-circus/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "jest-circus/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "jest-circus/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], "jest-circus/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-cli/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-cli/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "jest-cli/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "jest-circus/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "jest-cli/jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-config/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-config/babel-jest/@jest/transform": ["@jest/transform@30.2.0", "", { "dependencies": { "@babel/core": "^7.27.4", "@jest/types": "30.2.0", "@jridgewell/trace-mapping": "^0.3.25", "babel-plugin-istanbul": "^7.0.1", "chalk": "^4.1.2", "convert-source-map": "^2.0.0", "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.11", "jest-haste-map": "30.2.0", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "micromatch": "^4.0.8", "pirates": "^4.0.7", "slash": "^3.0.0", "write-file-atomic": "^5.0.1" } }, "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA=="], - - "jest-config/babel-jest/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "jest-config/babel-jest/babel-preset-jest": ["babel-preset-jest@30.2.0", "", { "dependencies": { "babel-plugin-jest-hoist": "30.2.0", "babel-preset-current-node-syntax": "^1.2.0" }, "peerDependencies": { "@babel/core": "^7.11.0 || ^8.0.0-beta.1" } }, "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ=="], - "jest-config/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "jest-config/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "jest-config/jest-environment-node/@jest/environment": ["@jest/environment@30.2.0", "", { "dependencies": { "@jest/fake-timers": "30.2.0", "@jest/types": "30.2.0", "@types/node": "*", "jest-mock": "30.2.0" } }, "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g=="], - - "jest-config/jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], - - "jest-config/jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "jest-config/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "jest-config/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-diff/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-each/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-config/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "jest-each/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "jest-diff/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-each/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "jest-diff/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "jest-each/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-leak-detector/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-each/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "jest-matcher-utils/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-environment-node/jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-message-util/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "jest-message-util/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-resolve/jest-haste-map/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], - - "jest-resolve/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "jest-resolve/jest-haste-map/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], + "jest-leak-detector/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-resolve/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], + "jest-leak-detector/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "jest-resolve/jest-util/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "jest-matcher-utils/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-resolve/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "jest-matcher-utils/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "jest-resolve/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "jest-message-util/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-resolve/jest-validate/@jest/types": ["@jest/types@30.2.0", "", { "dependencies": { "@jest/pattern": "30.0.1", "@jest/schemas": "30.0.5", "@types/istanbul-lib-coverage": "^2.0.6", "@types/istanbul-reports": "^3.0.4", "@types/node": "*", "@types/yargs": "^17.0.33", "chalk": "^4.1.2" } }, "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg=="], + "jest-message-util/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "jest-resolve/jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "jest-runner/@jest/environment/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], - - "jest-runner/@jest/environment/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "jest-runner/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "jest-runner/@jest/transform/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-runner/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - - "jest-runner/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-runner/jest-environment-node/@jest/fake-timers": ["@jest/fake-timers@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@sinonjs/fake-timers": "^13.0.0", "@types/node": "*", "jest-message-util": "30.2.0", "jest-mock": "30.2.0", "jest-util": "30.2.0" } }, "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw=="], - - "jest-runner/jest-environment-node/jest-mock": ["jest-mock@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "jest-util": "30.2.0" } }, "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw=="], - - "jest-runner/jest-environment-node/jest-validate": ["jest-validate@30.2.0", "", { "dependencies": { "@jest/get-type": "30.1.0", "@jest/types": "30.2.0", "camelcase": "^6.3.0", "chalk": "^4.1.2", "leven": "^3.1.0", "pretty-format": "30.2.0" } }, "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw=="], - - "jest-runner/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "jest-runner/jest-haste-map/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-runner/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "jest-runner/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "jest-runner/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "jest-runner/source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - - "jest-runtime/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - - "jest-runtime/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "jest-runtime/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], + "jest-runner/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], - "jest-runtime/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-runner/source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], "jest-runtime/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "jest-runtime/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "jest-runtime/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "jest-runtime/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - - "jest-runtime/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "jest-runtime/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "jest-snapshot/@jest/transform/babel-plugin-istanbul": ["babel-plugin-istanbul@7.0.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-instrument": "^6.0.2", "test-exclude": "^6.0.0" } }, "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA=="], - - "jest-snapshot/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "jest-snapshot/@jest/transform/jest-regex-util": ["jest-regex-util@30.0.1", "", {}, "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA=="], - - "jest-snapshot/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - - "jest-snapshot/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-snapshot/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "jest-snapshot/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - "jest-snapshot/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-watcher/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + "jest-snapshot/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "jest-watcher/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "jest-worker/jest-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="], - "jest-watcher/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + "jest-worker/jest-util/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -2668,9 +2429,13 @@ "log-symbols/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], - "metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "metro-babel-transformer/hermes-parser/hermes-estree": ["hermes-estree@0.35.0", "", {}, "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg=="], + + "metro/accepts/negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], - "metro/hermes-parser/hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + "metro/hermes-parser/hermes-estree": ["hermes-estree@0.35.0", "", {}, "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg=="], + + "metro/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "ora/chalk/ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], @@ -2678,72 +2443,22 @@ "ora/chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + "p-locate/p-limit/yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], - "@babel/highlight/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], - - "@babel/highlight/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], - - "@expo/cli/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], - - "@expo/config-plugins/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], - - "@expo/config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], - - "@expo/fingerprint/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], - - "@expo/metro-config/glob/minimatch/brace-expansion": ["brace-expansion@5.0.3", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA=="], + "@expo/fingerprint/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], - "@jest/console/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@jest/core/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "@jest/core/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "@jest/core/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@jest/core/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "@jest/core/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "@jest/globals/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - - "@jest/globals/@jest/environment/@jest/fake-timers/jest-util": ["jest-util@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "chalk": "^4.1.2", "ci-info": "^4.2.0", "graceful-fs": "^4.2.11", "picomatch": "^4.0.2" } }, "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA=="], - - "@jest/globals/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@jest/globals/jest-mock/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@jest/globals/jest-mock/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@jest/reporters/@jest/transform/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "@jest/reporters/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "@jest/reporters/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "@jest/reporters/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@jest/reporters/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "@jest/snapshot-utils/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@jest/test-result/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@jest/test-sequencer/jest-haste-map/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "@jest/test-sequencer/jest-haste-map/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@jest/test-sequencer/jest-haste-map/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@jest/test-sequencer/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "@react-native-harness/jest/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.55.0", "", {}, "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w=="], "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.55.0", "", {}, "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w=="], @@ -2768,102 +2483,44 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], - "expect/jest-mock/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "expect/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-changed-files/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-circus/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - - "jest-circus/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "jest-circus/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-cli/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-cli/jest-validate/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-config/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "jest-config/babel-jest/@jest/transform/jest-haste-map": ["jest-haste-map@30.2.0", "", { "dependencies": { "@jest/types": "30.2.0", "@types/node": "*", "anymatch": "^3.1.3", "fb-watchman": "^2.0.2", "graceful-fs": "^4.2.11", "jest-regex-util": "30.0.1", "jest-util": "30.2.0", "jest-worker": "30.2.0", "micromatch": "^4.0.8", "walker": "^1.0.8" }, "optionalDependencies": { "fsevents": "^2.3.3" } }, "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw=="], - - "jest-config/babel-jest/@jest/transform/write-file-atomic": ["write-file-atomic@5.0.1", "", { "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" } }, "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw=="], - - "jest-config/babel-jest/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "jest-config/babel-jest/babel-preset-jest/babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@30.2.0", "", { "dependencies": { "@types/babel__core": "^7.20.5" } }, "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA=="], + "jest-cli/jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "jest-config/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "jest-config/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "jest-config/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - "jest-config/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "jest-diff/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-each/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-each/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + "jest-environment-node/jest-validate/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], + + "jest-environment-node/jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + "jest-leak-detector/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "jest-matcher-utils/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-message-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-message-util/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-resolve/jest-haste-map/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-resolve/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "jest-resolve/jest-util/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-resolve/jest-validate/@jest/types/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-resolve/jest-validate/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - "jest-runner/@jest/environment/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - - "jest-runner/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "jest-runner/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "jest-runner/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "jest-runner/jest-environment-node/@jest/fake-timers/@sinonjs/fake-timers": ["@sinonjs/fake-timers@13.0.5", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw=="], - - "jest-runner/jest-environment-node/jest-validate/pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - - "jest-runtime/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "jest-runtime/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "jest-runtime/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + "jest-resolve/jest-validate/pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], "jest-runtime/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "jest-runtime/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "jest-runtime/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "jest-snapshot/@jest/transform/babel-plugin-istanbul/istanbul-lib-instrument": ["istanbul-lib-instrument@6.0.3", "", { "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" } }, "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q=="], - - "jest-snapshot/@jest/transform/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "jest-snapshot/@jest/transform/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - - "jest-snapshot/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "jest-snapshot/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-snapshot/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-watcher/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "log-symbols/chalk/ansi-styles/color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], "log-symbols/chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], @@ -2874,28 +2531,8 @@ "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], - "@babel/highlight/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], - - "@expo/cli/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "@expo/config-plugins/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "@expo/config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "@expo/fingerprint/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - - "@expo/metro-config/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], - "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], - "@jest/globals/@jest/environment/@jest/fake-timers/jest-util/ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], - - "@jest/globals/@jest/environment/@jest/fake-timers/jest-util/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], - - "@jest/test-sequencer/jest-haste-map/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "@react-native-harness/jest/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -2904,32 +2541,12 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - "expect/jest-mock/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "expect/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "jest-changed-files/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-cli/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-config/babel-jest/@jest/transform/jest-haste-map/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - - "jest-config/babel-jest/@jest/transform/jest-haste-map/jest-worker": ["jest-worker@30.2.0", "", { "dependencies": { "@types/node": "*", "@ungap/structured-clone": "^1.3.0", "jest-util": "30.2.0", "merge-stream": "^2.0.0", "supports-color": "^8.1.1" } }, "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g=="], - - "jest-config/babel-jest/@jest/transform/write-file-atomic/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], - - "jest-resolve/jest-haste-map/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "jest-resolve/jest-util/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - - "jest-resolve/jest-validate/@jest/types/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + "jest-environment-node/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "jest-resolve/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], - "jest-runner/jest-environment-node/jest-validate/pretty-format/@jest/schemas": ["@jest/schemas@30.0.5", "", { "dependencies": { "@sinclair/typebox": "^0.34.0" } }, "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA=="], - - "jest-snapshot/@jest/transform/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], "ora/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], @@ -2939,9 +2556,5 @@ "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "eslint-config-expo/@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "jest-config/babel-jest/@jest/transform/jest-haste-map/jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], - - "jest-runner/jest-environment-node/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], } } diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx new file mode 100644 index 00000000..01503660 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 1 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md b/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md new file mode 100644 index 00000000..357c8510 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md @@ -0,0 +1 @@ +Enable Expo inline modules in app config and add a minimal Kotlin or Swift inline module inside a watched project directory. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx new file mode 100644 index 00000000..1c024aec --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Inline module config + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json new file mode 100644 index 00000000..45a79570 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json @@ -0,0 +1,9 @@ +{ + "expo": { + "experiments": { + "inlineModules": { + "watchedDirectories": ["src/modules"] + } + } + } +} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt new file mode 100644 index 00000000..5195a634 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt @@ -0,0 +1,11 @@ +package expo.modules.deviceaudit + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition + +class DeviceAuditModule : Module() { + override fun definition() = ModuleDefinition { + Name("DeviceAuditModule") + Constant("source") { "inline" } + } +} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml new file mode 100644 index 00000000..4bdefe3b --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: inline-modules-enabled + description: "Must set expo.experiments.inlineModules in app config." + - id: watched-directory-valid + description: "Must place inline native files in a configured watched directory." + - id: module-dsl-used + description: "Must define the native module with Expo Module/ModuleDefinition DSL." + - id: prebuild-note + description: "Must make it clear that changing inlineModules config requires prebuild/build regeneration." diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx new file mode 100644 index 00000000..719400b3 --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 2 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md new file mode 100644 index 00000000..95b95361 --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md @@ -0,0 +1 @@ +Configure inline module watchedDirectories with valid project subdirectories and avoid invalid root, parent, duplicate, or special-character paths. diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json new file mode 100644 index 00000000..0c066de0 --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json @@ -0,0 +1,9 @@ +{ + "expo": { + "experiments": { + "inlineModules": { + "watchedDirectories": ["app", "src/modules"] + } + } + } +} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt new file mode 100644 index 00000000..87269e4d --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt @@ -0,0 +1,10 @@ +package expo.modules.directoryaudit + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition + +class DirectoryAuditModule : Module() { + override fun definition() = ModuleDefinition { + Name("DirectoryAuditModule") + } +} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml new file mode 100644 index 00000000..a001d3c1 --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: watched-directories-valid + description: "Must configure watchedDirectories as project subdirectories, not ./, /, ../, or parent directories." + - id: no-overlapping-watched-dirs + description: "Must not include both a directory and its nested child in watchedDirectories." + - id: no-special-router-group-path + description: "Must not put special-character route groups such as app/(tabs) in watchedDirectories." + - id: nested-files-covered-by-parent + description: "Must rely on the parent watched directory to include nested inline module files." diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx new file mode 100644 index 00000000..00b8b5e4 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 3 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md b/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md new file mode 100644 index 00000000..52401d58 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md @@ -0,0 +1 @@ +Create a Swift inline module whose file name, class name, and module Name all match. diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts new file mode 100644 index 00000000..942fed50 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts @@ -0,0 +1,3 @@ +import { requireNativeModule } from 'expo-modules-core' + +export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift new file mode 100644 index 00000000..97f88e75 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift @@ -0,0 +1,10 @@ +import ExpoModulesCore + +public class WeatherInlineModule: Module { + public func definition() -> ModuleDefinition { + Name("WeatherInlineModule") + Function("unit") { + return "celsius" + } + } +} diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml new file mode 100644 index 00000000..b5a33850 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: swift-file-class-match + description: "Must make the Swift file name match the Swift module class name." + - id: swift-name-matches-class + description: "Must set Name(\"...\") to the same module name or omit it only when inference is correct." + - id: uses-expo-modules-core + description: "Must import ExpoModulesCore and conform to Module." + - id: js-wrapper-same-name + description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx new file mode 100644 index 00000000..52d3bbb3 --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 4 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md new file mode 100644 index 00000000..1677a055 --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md @@ -0,0 +1 @@ +Create a Kotlin inline module whose file name, class name, and module Name all match. diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts new file mode 100644 index 00000000..942fed50 --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts @@ -0,0 +1,3 @@ +import { requireNativeModule } from 'expo-modules-core' + +export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt new file mode 100644 index 00000000..bebb1758 --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt @@ -0,0 +1,13 @@ +package expo.modules.weatherinline + +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition + +class WeatherInlineModule : Module() { + override fun definition() = ModuleDefinition { + Name("WeatherInlineModule") + Function("unit") { + "celsius" + } + } +} diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml new file mode 100644 index 00000000..17be49b6 --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: kotlin-file-class-match + description: "Must make the Kotlin file name match the Kotlin module class name." + - id: kotlin-name-matches-class + description: "Must set Name(\"...\") to the same module name or omit it only when inference is correct." + - id: uses-kotlin-module-dsl + description: "Must extend expo.modules.kotlin.modules.Module and return ModuleDefinition." + - id: js-wrapper-same-name + description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx new file mode 100644 index 00000000..b00f2f48 --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 5 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md new file mode 100644 index 00000000..f3bd8fca --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md @@ -0,0 +1 @@ +Wrap a native module with requireNativeModule from expo-modules-core and expose typed JS helpers. diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts new file mode 100644 index 00000000..3741dbba --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts @@ -0,0 +1,11 @@ +import { requireNativeModule } from 'expo-modules-core' + +type DeviceAuditModule = { + getBatteryLabelAsync(): Promise +} + +const NativeDeviceAudit = requireNativeModule('DeviceAudit') + +export async function getBatteryLabel() { + return NativeDeviceAudit.getBatteryLabelAsync() +} diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts new file mode 100644 index 00000000..8082f40b --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts @@ -0,0 +1 @@ +export { getBatteryLabel } from './NativeDeviceAudit' diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml new file mode 100644 index 00000000..ba312aff --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-require-native-module + description: "Must import requireNativeModule from expo-modules-core." + - id: typed-native-surface + description: "Must define a TypeScript type/interface for the native module surface." + - id: exports-js-helper + description: "Must export a JS helper instead of exposing an untyped native object everywhere." + - id: name-matches-native-module + description: "Must pass the exact native module name to requireNativeModule." diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx new file mode 100644 index 00000000..e86b33f3 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 6 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md new file mode 100644 index 00000000..52e91b0f --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md @@ -0,0 +1 @@ +Define an Expo module View with typed props, events, and a JS wrapper that forwards props safely. diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift new file mode 100644 index 00000000..c1fb573f --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift @@ -0,0 +1,13 @@ +import ExpoModulesCore + +public class AuditLabelModule: Module { + public func definition() -> ModuleDefinition { + Name("AuditLabel") + View(AuditLabelView.self) { + Prop("title") { (view: AuditLabelView, title: String) in + view.label.text = title + } + Events("onReady") + } + } +} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift new file mode 100644 index 00000000..6b252402 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift @@ -0,0 +1,5 @@ +import ExpoModulesCore + +final class AuditLabelView: ExpoView { + let label = UILabel() +} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx new file mode 100644 index 00000000..b95931b0 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx @@ -0,0 +1,8 @@ +import { requireNativeViewManager } from 'expo-modules-core' + +type Props = { + title: string + onReady?: () => void +} + +export default requireNativeViewManager('AuditLabel') diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml new file mode 100644 index 00000000..de8dafa1 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: view-definition-used + description: "Must define a View(...) in the native module definition." + - id: typed-props + description: "Must declare native view props in native code and in the JS wrapper." + - id: events-declared + description: "Must declare emitted events in the module definition and expose handlers in TS props." + - id: require-native-view-manager + description: "Must use requireNativeViewManager for the React wrapper." diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx new file mode 100644 index 00000000..d0f16e38 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 7 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md new file mode 100644 index 00000000..e63a67d9 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md @@ -0,0 +1 @@ +Configure Expo modules type generation with stable output paths and committed generated TypeScript surfaces. diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts new file mode 100644 index 00000000..4b80a156 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts @@ -0,0 +1,4 @@ +export type AuditResult = { + ok: boolean +} +export declare function audit(): Promise diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json new file mode 100644 index 00000000..09915d51 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json @@ -0,0 +1,6 @@ +{ + "platforms": ["ios", "android"], + "ios": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] }, + "apple": { "modules": ["AuditModule"] } +} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts new file mode 100644 index 00000000..4d049abc --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts @@ -0,0 +1,7 @@ +export type AuditResult = { + ok: boolean +} + +export async function audit(): Promise { + return { ok: true } +} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml new file mode 100644 index 00000000..85c0c136 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: expo-module-config-platforms + description: "Must keep expo-module.config.json platforms and module class names explicit." + - id: generated-types-stable-path + description: "Must write generated TypeScript declarations to a stable committed path." + - id: exports-types + description: "Must export the public TypeScript types from the package entrypoint." + - id: no-ephemeral-output-only + description: "Must not rely only on an ignored temp typegen output directory." diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx new file mode 100644 index 00000000..16649b59 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 8 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md new file mode 100644 index 00000000..c03236cf --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md @@ -0,0 +1 @@ +Create a config plugin that adds platform permission strings idempotently through Expo config-plugins. diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts new file mode 100644 index 00000000..cd173231 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts @@ -0,0 +1,7 @@ +export default { + expo: { + plugins: [ + ['./plugin/withAuditPermissions', { microphoneMessage: 'Allow audio audit recording.' }], + ], + }, +} diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts new file mode 100644 index 00000000..d48ed832 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts @@ -0,0 +1,16 @@ +import { AndroidConfig, ConfigPlugin, IOSConfig, withAndroidManifest, withInfoPlist } from 'expo/config-plugins' + +const MICROPHONE = 'android.permission.RECORD_AUDIO' + +export const withAuditPermissions: ConfigPlugin<{ microphoneMessage: string }> = (config, props) => { + config = withInfoPlist(config, (nextConfig) => { + nextConfig.modResults.NSMicrophoneUsageDescription = props.microphoneMessage + return nextConfig + }) + return withAndroidManifest(config, (nextConfig) => { + AndroidConfig.Permissions.addPermission(nextConfig.modResults, MICROPHONE) + return nextConfig + }) +} + +export default withAuditPermissions diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml new file mode 100644 index 00000000..b5027555 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: config-plugin-export + description: "Must export a ConfigPlugin from the plugin file." + - id: ios-permission-string + description: "Must write the iOS permission string through withInfoPlist or equivalent config-plugin mod." + - id: android-permission-idempotent + description: "Must add Android permission through AndroidConfig.Permissions helpers or idempotent manifest editing." + - id: plugin-used-in-app-config + description: "Must wire the local config plugin into app.config.ts/app.json." diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx new file mode 100644 index 00000000..63e3a7bb --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 9 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md new file mode 100644 index 00000000..9ab48af6 --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md @@ -0,0 +1 @@ +Document/script a noninteractive create-expo-module scaffold with deterministic package name and platforms. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md new file mode 100644 index 00000000..82341920 --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md @@ -0,0 +1,3 @@ +# expo-audit-module scaffold + +Run the script from the repository root to create the module noninteractively with fixed name and platforms. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh new file mode 100644 index 00000000..18799f2b --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +npx create-expo-module@latest expo-audit-module --platforms ios,android --package-name expo-audit-module --no-install diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml new file mode 100644 index 00000000..2324e340 --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: noninteractive-command + description: "Must provide a noninteractive create-expo-module command or script." + - id: fixed-package-name + description: "Must set a deterministic module/package name." + - id: fixed-platforms + description: "Must specify target platforms explicitly." + - id: no-interactive-prompts + description: "Must avoid instructions that require answering interactive prompts during evaluation." diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx new file mode 100644 index 00000000..e6fa0071 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo Modules 10 + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md b/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md new file mode 100644 index 00000000..0411f60d --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md @@ -0,0 +1 @@ +Add a new platform implementation to an Expo module without breaking autolinking config or JS exports. diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json new file mode 100644 index 00000000..497ef4df --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json @@ -0,0 +1,6 @@ +{ + "platforms": ["ios", "android", "web"], + "ios": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] }, + "web": { "modules": ["src/AuditModule.web.ts"] } +} diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts new file mode 100644 index 00000000..f3ab2d43 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts @@ -0,0 +1,5 @@ +export default { + getPlatform() { + return 'web' + }, +} diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts new file mode 100644 index 00000000..7721ee50 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts @@ -0,0 +1,7 @@ +import { requireNativeModule } from 'expo-modules-core' + +type AuditModule = { + getPlatform(): string +} + +export default requireNativeModule('AuditModule') diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml b/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml new file mode 100644 index 00000000..b313f88c --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: platform-added-to-config + description: "Must add the new platform to expo-module.config.json." + - id: platform-implementation-file + description: "Must include an implementation file for the added platform." + - id: js-export-preserved + description: "Must preserve the JS/TS public export surface." + - id: autolinking-not-broken + description: "Must not remove existing iOS/Android autolinking module declarations while adding the new platform." diff --git a/evals/expo-modules/README.md b/evals/expo-modules/README.md new file mode 100644 index 00000000..3b606126 --- /dev/null +++ b/evals/expo-modules/README.md @@ -0,0 +1,31 @@ +# Expo Modules eval category + +## category overview + +Expo Modules evals are statically judged file tasks covering inline modules, native module naming, JS wrappers, config plugins, type generation, and module scaffolding. + +## library baseline and naming + +- Baseline: Expo SDK 56 Expo Modules API. +- Inline modules are SDK 56 experimental behavior and are judged from app config plus Kotlin/Swift files. +- Eval IDs start with two digits and the `rn-expo-modules-` prefix. + +## best practices + +### official best-practice sources + +- Expo Modules API overview: https://docs.expo.dev/modules/overview/ +- Expo Modules API reference: https://docs.expo.dev/modules/module-api/ +- Inline modules reference: https://docs.expo.dev/modules/inline-modules-reference/ +- Type generation reference: https://docs.expo.dev/modules/typescript/ +- expo-module.config.json reference: https://docs.expo.dev/modules/module-config/ +- Config plugins introduction: https://docs.expo.dev/config-plugins/introduction/ + +### best-practice inventory + +- M1: Enable inline modules through expo.experiments.inlineModules and valid watchedDirectories. +- M2: Keep inline module file names, class names, and module names aligned. +- M3: Wrap native modules from JS with requireNativeModule or requireNativeViewManager and typed helpers. +- M4: Declare native view props/events in both native module definitions and JS wrappers. +- M5: Keep type generation output stable and committed when it is part of the public surface. +- M6: Write config plugins through Expo config-plugin mods and make permission changes idempotent. diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/index.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md new file mode 100644 index 00000000..6b0890d0 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md @@ -0,0 +1 @@ +Migrate an Expo Router layout to SDK 56 import boundaries: use expo-router exports in app code and avoid direct @react-navigation imports. diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx new file mode 100644 index 00000000..81c9df68 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx @@ -0,0 +1,6 @@ +import { Stack, useNavigation } from 'expo-router' + +export default function Layout() { + useNavigation() + return +} diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx new file mode 100644 index 00000000..307c5221 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx @@ -0,0 +1,11 @@ +import { Link } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + Details + + ) +} diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml new file mode 100644 index 00000000..c3b72eb8 --- /dev/null +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: imports-from-expo-router + description: "Must import router hooks/themes/navigation helpers from expo-router exports rather than direct @react-navigation packages." + - id: no-direct-react-navigation-imports + description: "Must not import from @react-navigation/native or @react-navigation/native-stack in app route files." + - id: keeps-file-system-layout + description: "Must keep navigation defined through Expo Router layout and route files." + - id: uses-sdk56-exported-hooks + description: "Must use SDK 56-compatible exports such as useNavigation from expo-router." diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md new file mode 100644 index 00000000..3aaa068f --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md @@ -0,0 +1 @@ +Implement a stack layout using Expo Router Stack, not createNativeStackNavigator, and keep route files file-system based. diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/_layout.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/_layout.tsx new file mode 100644 index 00000000..40d1bac8 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/_layout.tsx @@ -0,0 +1,10 @@ +import { Stack } from 'expo-router' + +export default function Layout() { + return ( + + + + + ) +} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx new file mode 100644 index 00000000..97fa5eb9 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx @@ -0,0 +1,7 @@ +import { useLocalSearchParams } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Details() { + const { id } = useLocalSearchParams<{ id?: string }>() + return Product {id ?? 'unknown'} +} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx new file mode 100644 index 00000000..307c5221 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx @@ -0,0 +1,11 @@ +import { Link } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + Details + + ) +} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml new file mode 100644 index 00000000..31290969 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: uses-expo-router-stack + description: "Must render Stack from expo-router in _layout.tsx." + - id: no-create-native-stack-navigator + description: "Must not call createNativeStackNavigator or NavigationContainer in Expo Router app code." + - id: registers-screens-by-name + description: "Must configure Stack.Screen entries by file-route names." + - id: route-file-present + description: "Must include a route file matching each configured screen." diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md new file mode 100644 index 00000000..a7214509 --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md @@ -0,0 +1 @@ +Compose Expo Router Stack header buttons/search/title with Stack child components and route-level options. diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx new file mode 100644 index 00000000..0e379e8e --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx @@ -0,0 +1,14 @@ +import { Stack } from 'expo-router' +import { Alert } from 'react-native' + +export default function Layout() { + return ( + + + + Alert.alert('New item')} /> + + + + ) +} diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx new file mode 100644 index 00000000..307c5221 --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx @@ -0,0 +1,11 @@ +import { Link } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + Details + + ) +} diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml new file mode 100644 index 00000000..e4dbbeb5 --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: uses-stack-toolbar-components + description: "Must compose header actions with Stack.Toolbar child components." + - id: route-options-in-layout + description: "Must keep screen options in Expo Router Stack layout/screen configuration." + - id: action-callback-defined + description: "Must wire header action callbacks to deterministic handlers." + - id: no-react-navigation-headerleft + description: "Must not import React Navigation header types/components directly." diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md new file mode 100644 index 00000000..b2426cfd --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md @@ -0,0 +1 @@ +Implement an iOS large-title screen whose scroll content is the first child and whose options live in Expo Router Stack. diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx new file mode 100644 index 00000000..ae441594 --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx @@ -0,0 +1,5 @@ +import { Stack } from 'expo-router' + +export default function Layout() { + return +} diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx new file mode 100644 index 00000000..598d2a13 --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx @@ -0,0 +1,9 @@ +import { ScrollView, Text } from 'react-native' + +export default function Index() { + return ( + + Large-title content starts inside the scroll view. + + ) +} diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml new file mode 100644 index 00000000..4a23e0b4 --- /dev/null +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: large-title-option + description: "Must set headerLargeTitle or equivalent large-title Stack option." + - id: scroll-view-first-child + description: "Must make the page content start with a ScrollView or compatible scrollable child." + - id: content-inset-adjustment + description: "Must configure automatic content inset behavior for iOS large titles." + - id: stack-only + description: "Must use Expo Router Stack, not a manually created native stack." diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md new file mode 100644 index 00000000..0a99b8ba --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md @@ -0,0 +1 @@ +Build native tabs with expo-router/unstable-native-tabs and explicit Trigger entries for every tab. diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx new file mode 100644 index 00000000..1ef12db8 --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx @@ -0,0 +1,16 @@ +import { NativeTabs } from 'expo-router/unstable-native-tabs' + +export default function Layout() { + return ( + + + Home + + + + Settings + + + + ) +} diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx new file mode 100644 index 00000000..4d398c68 --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function Home() { return Home } diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx new file mode 100644 index 00000000..a21db765 --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function Settings() { return Settings } diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml new file mode 100644 index 00000000..95b40fcd --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: imports-unstable-native-tabs + description: "Must import NativeTabs from expo-router/unstable-native-tabs." + - id: uses-trigger-api + description: "Must use NativeTabs.Trigger entries instead of Tabs.Screen for this native-tabs layout." + - id: trigger-names-match-routes + description: "Must ensure every Trigger name matches a route file." + - id: no-react-navigation-tabs + description: "Must not import bottom-tabs from @react-navigation for native tabs." diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md new file mode 100644 index 00000000..da015cc8 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md @@ -0,0 +1 @@ +Configure native tabs with selected/default labels, icons, and badges using NativeTabs.Trigger child APIs. diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx new file mode 100644 index 00000000..61abb1b7 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx @@ -0,0 +1,16 @@ +import { NativeTabs } from 'expo-router/unstable-native-tabs' + +export default function Layout() { + return ( + + + Home + + + + Settings + 2 + + + ) +} diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx new file mode 100644 index 00000000..4d398c68 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function Home() { return Home } diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx new file mode 100644 index 00000000..a21db765 --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function Settings() { return Settings } diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml new file mode 100644 index 00000000..1c6c392b --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: selected-default-icon-state + description: "Must configure selected/default icon or label state through NativeTabs.Trigger children." + - id: badge-or-label-child-api + description: "Must use NativeTabs.Trigger.Label/Icon/Badge child APIs for per-tab presentation." + - id: route-name-alignment + description: "Must align tab trigger names with file routes." + - id: no-generic-tabs-api + description: "Must not use generic Expo Router Tabs for this native-tabs task." diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md new file mode 100644 index 00000000..4d8050a2 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md @@ -0,0 +1 @@ +Protect authenticated Expo Router routes with Stack.Protected or Tabs.Protected and a deterministic signed-out fallback. diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx new file mode 100644 index 00000000..a71b6cef --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx @@ -0,0 +1,16 @@ +import { Stack } from 'expo-router' + +const signedIn = false + +export default function Layout() { + return ( + + + + + + + + + ) +} diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx new file mode 100644 index 00000000..6f710168 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function Account() { return Account } diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx new file mode 100644 index 00000000..4e347807 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function SignIn() { return Sign in } diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml new file mode 100644 index 00000000..1f4c6b6e --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: uses-protected-routes + description: "Must use Stack.Protected, Tabs.Protected, or the Expo Router protected route API." + - id: signed-out-fallback + description: "Must provide a deterministic signed-out fallback route." + - id: guard-boolean-explicit + description: "Must pass explicit guard booleans derived from auth state." + - id: no-redirect-loop + description: "Must avoid unconditional redirects that can loop between protected and sign-in routes." diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md new file mode 100644 index 00000000..9ca4fc50 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md @@ -0,0 +1 @@ +Implement navigation with serializable search params and decode them safely with Expo Router hooks. diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx new file mode 100644 index 00000000..61625f48 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx @@ -0,0 +1,2 @@ +import { Stack } from 'expo-router' +export default function Layout() { return } diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx new file mode 100644 index 00000000..84e5e26d --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx @@ -0,0 +1,7 @@ +import { useLocalSearchParams } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Details() { + const { id, tab } = useLocalSearchParams<{ id?: string; tab?: string }>() + return {String(id ?? 'missing')} - {String(tab ?? 'overview')} +} diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx new file mode 100644 index 00000000..307c5221 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx @@ -0,0 +1,11 @@ +import { Link } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + Details + + ) +} diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml new file mode 100644 index 00000000..10664192 --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: serializable-link-params + description: "Must navigate with serializable primitive search params." + - id: uses-local-search-params + description: "Must read route params with useLocalSearchParams or useGlobalSearchParams from expo-router." + - id: param-fallbacks + description: "Must handle missing params with fallback values." + - id: no-object-function-params + description: "Must not pass functions, class instances, or non-serializable objects as route params." diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md b/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md new file mode 100644 index 00000000..426ef90e --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md @@ -0,0 +1 @@ +Enable Expo Router data loaders for web and use loader/useLoaderData in a route. diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx new file mode 100644 index 00000000..61625f48 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx @@ -0,0 +1,2 @@ +import { Stack } from 'expo-router' +export default function Layout() { return } diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json new file mode 100644 index 00000000..ceca201d --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json @@ -0,0 +1,11 @@ +{ + "expo": { + "plugins": [ + ["expo-router", { "asyncRoutes": true }] + ], + "web": { + "bundler": "metro", + "output": "server" + } + } +} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx new file mode 100644 index 00000000..5d646699 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx @@ -0,0 +1,11 @@ +import { useLoaderData } from 'expo-router' +import { Text } from 'react-native' + +export async function loader() { + return { greeting: 'Loaded on the route boundary' } +} + +export default function Index() { + const data = useLoaderData() + return {data.greeting} +} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml new file mode 100644 index 00000000..a3019503 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: loader-exported-from-route + description: "Must export a loader from the route module." + - id: uses-use-loader-data + description: "Must read loader results with useLoaderData typed to the loader." + - id: router-plugin-configured + description: "Must configure expo-router/app config for data-loader compatible web/server output." + - id: no-client-fetch-duplication + description: "Must not duplicate the same data fetch in a client mount effect." diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md new file mode 100644 index 00000000..21bfe7f5 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md @@ -0,0 +1 @@ +Split static loader-safe data from server-only code and avoid importing server secrets into client routes. diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx new file mode 100644 index 00000000..61625f48 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx @@ -0,0 +1,2 @@ +import { Stack } from 'expo-router' +export default function Layout() { return } diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx new file mode 100644 index 00000000..d2313dba --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx @@ -0,0 +1,12 @@ +import { useLoaderData } from 'expo-router' +import { Text } from 'react-native' +import { readProfile } from './server/profile.server' + +export async function loader() { + return readProfile() +} + +export default function Profile() { + const profile = useLoaderData() + return {profile.name} +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts new file mode 100644 index 00000000..8e74015f --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts @@ -0,0 +1,3 @@ +export async function readProfile() { + return { name: process.env.PROFILE_NAME ?? 'Expo' } +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml new file mode 100644 index 00000000..003357c4 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: server-only-code-isolated + description: "Must place server-only secret/env access in a server-only module or loader boundary." + - id: client-route-uses-loader-data + description: "Must render route UI from useLoaderData rather than importing secrets directly." + - id: static-loader-data-serializable + description: "Must return serializable data from loader functions." + - id: no-secret-in-client-component + description: "Must not read process.env secrets in the client component body." diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx new file mode 100644 index 00000000..dee6ae56 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx @@ -0,0 +1,13 @@ +import { Text, View } from 'react-native' + +export function SuspenseFallback() { + return Loading... +} + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md new file mode 100644 index 00000000..b71796ac --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md @@ -0,0 +1 @@ +Use Expo Router's route-level SuspenseFallback export for async route content. diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx new file mode 100644 index 00000000..99996670 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx @@ -0,0 +1,5 @@ +import { Stack } from 'expo-router' + +export default function Layout() { + return +} diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx new file mode 100644 index 00000000..b76776db --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx @@ -0,0 +1,13 @@ +import { Text, View } from 'react-native' + +export function SuspenseFallback() { + return Loading route... +} + +export default function Index() { + return ( + + Async route content + + ) +} diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml new file mode 100644 index 00000000..037136f6 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: uses-suspense-fallback + description: "Must export a route-level SuspenseFallback function and must not render expo-router's internal SuspenseFallback component directly." + - id: fallback-has-deterministic-ui + description: "Must render a deterministic fallback UI while async route content is pending." + - id: stack-remains-rendered + description: "Must still render the nested Stack/Slot route outlet." + - id: no-global-loading-hack + description: "Must not replace the route outlet with a permanent loading screen." diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx new file mode 100644 index 00000000..cb1576d3 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Layout() { + return Replace with Expo Router layout. +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx new file mode 100644 index 00000000..66f93c34 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx @@ -0,0 +1,9 @@ +import { Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + + ) +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md b/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md new file mode 100644 index 00000000..70e9f4cc --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md @@ -0,0 +1 @@ +Implement a +not-found route that has priority over catch-all content and gives users a route back home. diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx new file mode 100644 index 00000000..344f8417 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx @@ -0,0 +1,6 @@ +import { Link, Unmatched } from 'expo-router' +import { Text, View } from 'react-native' + +export default function NotFound() { + return Missing routeGo home +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx new file mode 100644 index 00000000..a976440e --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx @@ -0,0 +1,2 @@ +import { Text } from 'react-native' +export default function CatchAll() { return Known catch-all content } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx new file mode 100644 index 00000000..61625f48 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx @@ -0,0 +1,2 @@ +import { Stack } from 'expo-router' +export default function Layout() { return } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml b/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml new file mode 100644 index 00000000..c0b57674 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: plus-not-found-route + description: "Must implement +not-found.tsx as the not-found route." + - id: uses-unmatched-or-home-link + description: "Must render Unmatched or equivalent missing-route context plus a link back home." + - id: catch-all-does-not-shadow-not-found + description: "Must not rely only on a catch-all route for unknown routes." + - id: deterministic-not-found-copy + description: "Must render deterministic not-found UI." diff --git a/evals/expo-router/README.md b/evals/expo-router/README.md new file mode 100644 index 00000000..d3b9dd59 --- /dev/null +++ b/evals/expo-router/README.md @@ -0,0 +1,30 @@ +# Expo Router eval category + +## category overview + +Expo Router evals cover SDK 56 route-file navigation behavior, import boundaries, protected routes, native tabs, data loaders, suspense fallbacks, and not-found routing. + +## library baseline and naming + +- Baseline: expo-router 56.x with Expo SDK 56. +- App code should use Expo Router exports and route files. It should not duplicate generic React Navigation evals covered by the navigation category. +- Eval IDs start with two digits and the `rn-expo-router-` prefix. + +## best practices + +### official best-practice sources + +- Expo Router SDK 55 to 56 migration: https://docs.expo.dev/router/migrate/sdk-55-to-56/ +- Expo Router native tabs: https://docs.expo.dev/router/advanced/native-tabs/ +- Expo Router data loaders: https://docs.expo.dev/router/web/data-loaders/ +- Expo Router protected routes: https://docs.expo.dev/router/advanced/protected/ +- Expo Router stack: https://docs.expo.dev/router/advanced/stack/ + +### best-practice inventory + +- R1: In SDK 56 app code, import navigation helpers from expo-router rather than direct React Navigation packages. +- R2: Keep navigation structure in file-system routes and Expo Router layouts. +- R3: Use NativeTabs Trigger child APIs for native tabs rather than generic tab screens. +- R4: Keep search params serializable and decode missing values defensively. +- R5: Keep server/data-loader boundaries explicit and avoid client-side secret access. +- R6: Use first-class protected, suspense, and not-found route APIs instead of redirect or catch-all hacks. diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx new file mode 100644 index 00000000..a9f996af --- /dev/null +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Camera permission retry + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md new file mode 100644 index 00000000..404e6abe --- /dev/null +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md @@ -0,0 +1 @@ +Build a production-ready camera entry flow with expo-camera. Request camera access only when the user initiates it, handle retry and settings-recovery states, keep permission state accurate after returning from settings, and render CameraView only while access is granted. diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx new file mode 100644 index 00000000..7f7c718d --- /dev/null +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx @@ -0,0 +1,78 @@ +import { CameraView, useCameraPermissions } from 'expo-camera' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [permission, requestPermission, getPermission] = useCameraPermissions() + const [requesting, setRequesting] = useState(false) + + const state = requesting ? 'requesting' : permission?.granted ? 'granted' : permission?.canAskAgain === false ? 'blocked' : 'denied' + + useEffect(() => { + const sub = AppState.addEventListener('change', (nextState) => { + if (nextState === 'active') void getPermission() + }) + return () => sub.remove() + }, [getPermission]) + + const request = async () => { + if (requesting || state === 'blocked') return + setRequesting(true) + try { + await requestPermission() + } finally { + setRequesting(false) + } + } + + return ( + + Camera access + {permission?.granted ? : Preview unavailable until camera permission is granted.} + Request or retry + {state === 'blocked' ? Linking.openSettings()} style={styles.action}>Open settings : null} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml new file mode 100644 index 00000000..c86a4caa --- /dev/null +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml @@ -0,0 +1,17 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: permission-request-on-demand + description: "Must call camera permission request APIs only from a user-triggered action, not from initial render or an unconditional mount effect." + - id: denied-flow-retry-and-settings + description: "Must support denied retry and blocked recovery by retrying while permission.canAskAgain is true and calling Linking.openSettings() when canAskAgain is false." + - id: lifecycle-permission-refresh + description: "Must refresh camera permission when AppState changes back to active using the hook getter or getCameraPermissionsAsync()." + - id: single-flight-permission-request + description: "Must prevent overlapping permission prompts with a request-in-flight state or equivalent guard." + - id: expo-camera-grant-gated-preview + description: "Must render CameraView only when the current permission object is granted and show deterministic fallback UI otherwise." + - id: implementation-expo-camera-current-api + description: "Must use CameraView and useCameraPermissions or current get/request camera permission APIs from expo-camera." diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md deleted file mode 100644 index 37fe67e9..00000000 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Build a production-ready camera entry flow with expo-camera. Request camera access only when the user initiates it, handle all permission outcomes with clear retry/recovery UX, keep permission state accurate across app lifecycle transitions (including returning from system settings), and render camera preview only when access is currently available diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/reference/App.tsx b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/reference/App.tsx deleted file mode 100644 index 397b244f..00000000 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/reference/App.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import { CameraView, useCameraPermissions } from 'expo-camera' -import React, { useCallback, useMemo, useState } from 'react' -import { - AppState, - Linking, - Pressable, - StyleSheet, - Text, - View, -} from 'react-native' - -type FlowState = 'idle' | 'granted' | 'denied' | 'blocked' | 'requesting' - -export default function App() { - const [permission, requestPermission, getPermission] = useCameraPermissions() - const [requesting, setRequesting] = useState(false) - - const flowState = ((): FlowState => { - if (requesting) return 'requesting' - if (!permission || permission.status === 'undetermined') return 'idle' - if (permission.granted) return 'granted' - return permission.canAskAgain ? 'denied' : 'blocked' - })() - - const refreshPermission = async () => { - return getPermission() - } - - React.useEffect(() => { - const sub = AppState.addEventListener('change', (s) => { - if (s === 'active') void refreshPermission() - }) - return () => sub.remove() - }, [refreshPermission]) - - const requestCameraPermissionAction = async () => { - if (requesting || flowState === 'blocked') return - setRequesting(true) - try { - await requestPermission() - } finally { - setRequesting(false) - } - } - - const statusText = { - idle: 'Camera permission not requested yet.', - requesting: 'Requesting camera permission...', - granted: 'Camera permission granted. Preview is enabled.', - denied: 'Camera permission denied. You can retry the request.', - blocked: 'Camera access is blocked. Enable it from system settings.', - }[flowState] - - return ( - - Camera Access - {statusText} - - {flowState === 'granted' ? ( - - - - ) : ( - - Preview unavailable - - Use retry or open settings to recover access. - - - )} - - - - Request / Retry - - - - Refresh state - - - {flowState === 'blocked' && ( - Linking.openSettings()} - style={styles.secondaryButton} - > - Open settings - - )} - - - ) -} - -const styles = StyleSheet.create({ - container: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - paddingHorizontal: 20, - rowGap: 12, - }, - title: { - fontSize: 20, - fontWeight: '600', - }, - status: { - color: '#374151', - textAlign: 'center', - }, - previewWrap: { - borderRadius: 12, - height: 220, - overflow: 'hidden', - width: '100%', - }, - preview: { - flex: 1, - }, - degradedCard: { - alignItems: 'center', - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 16, - width: '100%', - }, - degradedTitle: { - fontSize: 16, - fontWeight: '600', - }, - degradedBody: { - color: '#4b5563', - marginTop: 6, - textAlign: 'center', - }, - actions: { - rowGap: 10, - width: '100%', - }, - button: { - alignItems: 'center', - backgroundColor: '#111827', - borderRadius: 10, - paddingVertical: 12, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - secondaryButton: { - alignItems: 'center', - borderColor: '#9ca3af', - borderRadius: 10, - borderWidth: 1, - paddingVertical: 12, - }, - secondaryButtonText: { - color: '#111827', - fontWeight: '600', - }, - disabledButton: { - opacity: 0.5, - }, -}) diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/requirements.yaml b/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/requirements.yaml deleted file mode 100644 index 22c40cc7..00000000 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/requirements.yaml +++ /dev/null @@ -1,19 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: permission-request-on-demand - description: Must call `requestPermission` from `useCameraPermissions()` only from a user-triggered action (for example `Pressable.onPress`), not on initial mount. - - id: denied-flow-retry-and-settings - description: Must support denied and blocked flows by retrying with `requestPermission` and using `Linking.openSettings()` when `permission.canAskAgain` is false. - - id: lifecycle-permission-refresh - description: Must refresh permission state on app foreground with `AppState.addEventListener('change', ...)` and a permission refresh call (`getPermission` / `getCameraPermissionsAsync`). - - id: degraded-path-no-crash - description: Must render a deterministic fallback `View`/`Text` path when permission is unavailable instead of rendering `CameraView`. - - id: single-flight-permission-request - description: Must prevent concurrent permission requests by guarding `requestPermission` with an in-flight state (for example `requesting`). - - id: expo-camera-grant-gated-preview - description: Must render `CameraView` only when `permission.granted` is true, with deterministic denied/blocked fallback UI otherwise. - - id: implementation-expo-camera-cameraview-api - description: Must implement preview with `CameraView` and permission handling with `expo-camera` APIs used by the sample (`useCameraPermissions` with request/get methods, or `getCameraPermissionsAsync`/`requestCameraPermissionsAsync`). diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx new file mode 100644 index 00000000..600aafa7 --- /dev/null +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Camera active lifecycle + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md new file mode 100644 index 00000000..74ea2bd3 --- /dev/null +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md @@ -0,0 +1 @@ +Implement a camera preview that pauses native camera work when the screen is backgrounded, manually disabled, or no longer focused, and fully unmounts CameraView when access is not available. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx new file mode 100644 index 00000000..ef6d93ce --- /dev/null +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx @@ -0,0 +1,67 @@ +import { CameraView, useCameraPermissions } from 'expo-camera' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [permission, requestPermission] = useCameraPermissions() + const [appActive, setAppActive] = useState(AppState.currentState === 'active') + const [previewEnabled, setPreviewEnabled] = useState(true) + + useEffect(() => { + const sub = AppState.addEventListener('change', (state) => setAppActive(state === 'active')) + return () => sub.remove() + }, []) + + const cameraActive = Boolean(permission?.granted && appActive && previewEnabled) + + return ( + + Lifecycle camera + {permission?.granted ? : Camera is not mounted until permission is granted.} + requestPermission()} style={styles.action}>Grant camera + setPreviewEnabled((value) => !value)} style={styles.action}>{previewEnabled ? 'Pause preview' : 'Resume preview'} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml new file mode 100644 index 00000000..24d3ab5f --- /dev/null +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: camera-active-derived-from-visibility + description: "Must pass CameraView an active prop derived from foreground/focus state and user-enabled preview state." + - id: camera-appstate-background-pauses + description: "Must listen to AppState and set active false when the app leaves the active state." + - id: camera-view-unmounted-without-permission + description: "Must not render CameraView at all when camera permission is not granted." + - id: manual-preview-toggle + description: "Must expose a user action that toggles the preview without losing permission state." + - id: cleanup-appstate-subscription + description: "Must remove the AppState listener on unmount." diff --git a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx similarity index 62% rename from evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx rename to evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx index cc274570..126173d9 100644 --- a/evals/expo-sdk/01-rn-perm-expo-camera-request-denied-retry/app/App.tsx +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx @@ -1,22 +1,12 @@ import { Pressable, StyleSheet, Text, View } from 'react-native' -async function requestCameraPermissionAction() { - // No-op - return 'pending' -} - export default function App() { return ( - Camera Access - - Request, retry, and recover camera permission. - - requestCameraPermissionAction()} - > - Open + Camera barcode and audio + Replace this scaffold with the requested Expo implementation. + + Start ) @@ -38,6 +28,7 @@ const styles = StyleSheet.create({ backgroundColor: '#fff', flex: 1, justifyContent: 'center', + padding: 20, rowGap: 10, }, subtitle: { @@ -48,5 +39,6 @@ const styles = StyleSheet.create({ color: '#111827', fontSize: 20, fontWeight: '600', + textAlign: 'center', }, }) diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md new file mode 100644 index 00000000..546fc5c9 --- /dev/null +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md @@ -0,0 +1 @@ +Build a combined barcode scanner and video-ready camera screen with expo-camera. Configure barcode types explicitly, avoid stale BarCodeScanner APIs, and request microphone permission only when the user enables video capture with audio. diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx new file mode 100644 index 00000000..5595a269 --- /dev/null +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx @@ -0,0 +1,80 @@ +import { CameraView, useCameraPermissions, useMicrophonePermissions } from 'expo-camera' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [cameraPermission, requestCamera] = useCameraPermissions() + const [micPermission, requestMic] = useMicrophonePermissions() + const [lastScan, setLastScan] = useState('') + const [audioEnabled, setAudioEnabled] = useState(false) + const lastScanRef = useRef('') + + const enableAudio = async () => { + const result = await requestMic() + setAudioEnabled(result.granted) + } + + return ( + + Scanner + {cameraPermission?.granted ? ( + { + if (event.data === lastScanRef.current) return + lastScanRef.current = event.data + setLastScan(event.data) + }} + style={styles.media} + /> + ) : Grant camera permission to scan.} + Last scan: {lastScan || 'none'} + requestCamera()} style={styles.action}>Grant camera + {micPermission?.granted ? 'Audio ready' : 'Enable audio'} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml new file mode 100644 index 00000000..98bd6085 --- /dev/null +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-camera-view-barcode-settings + description: "Must use CameraView with barcodeScannerSettings and onBarcodeScanned instead of the deprecated BarCodeScanner package/API." + - id: limits-barcode-types + description: "Must configure a deterministic barcodeTypes allowlist instead of accepting every type implicitly." + - id: deduplicates-scan-results + description: "Must debounce or deduplicate repeated barcode scan events before updating state." + - id: microphone-request-on-video-intent + description: "Must request microphone permission only from the user action that enables video/audio capture." + - id: audio-gated-video-mode + description: "Must not enable audio recording controls unless microphone permission is granted or the camera is explicitly muted." diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx new file mode 100644 index 00000000..e5edae59 --- /dev/null +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + ImagePicker canceled guard + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md new file mode 100644 index 00000000..5cb5e7d5 --- /dev/null +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md @@ -0,0 +1 @@ +Implement an image picker flow that handles cancellation safely, reads the current SDK result shape, and renders a deterministic empty state when no asset was selected. diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx new file mode 100644 index 00000000..4d54838b --- /dev/null +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx @@ -0,0 +1,73 @@ +import * as ImagePicker from 'expo-image-picker' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [assetUri, setAssetUri] = useState(null) + const [message, setMessage] = useState('No image selected.') + + const pick = async () => { + const result = await ImagePicker.launchImageLibraryAsync({ + allowsEditing: true, + mediaTypes: ['images'], + quality: 0.8, + }) + if (result.canceled || !result.assets?.length) { + setAssetUri(null) + setMessage('Selection canceled.') + return + } + setAssetUri(result.assets[0].uri) + setMessage(result.assets[0].fileName ?? 'Image selected.') + } + + return ( + + Image picker + {assetUri ? : {message}} + Choose image + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml new file mode 100644 index 00000000..e2b93f1a --- /dev/null +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-current-canceled-spelling + description: "Must check result.canceled, not the old result.cancelled spelling." + - id: assets-null-guard + description: "Must guard result.assets before indexing because canceled results have assets: null." + - id: no-launch-on-mount + description: "Must call launchImageLibraryAsync only from a user action." + - id: uses-current-media-types-array + description: "Must use the current MediaType array form such as mediaTypes: [\"images\"] rather than depending on deprecated MediaTypeOptions." + - id: renders-empty-state + description: "Must show a stable empty/canceled UI path without crashing when the user cancels." diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx new file mode 100644 index 00000000..99be2f5d --- /dev/null +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + ImagePicker video permission nuance + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md new file mode 100644 index 00000000..406c1587 --- /dev/null +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md @@ -0,0 +1 @@ +Build a video-library picker that models media-library permission separately from picking, handles limited/denied access, and uses the current mediaTypes value shape. diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx new file mode 100644 index 00000000..5925b540 --- /dev/null +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx @@ -0,0 +1,72 @@ +import * as ImagePicker from 'expo-image-picker' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [status, setStatus] = useState('Permission not requested.') + const [videoUri, setVideoUri] = useState(null) + + const pickVideo = async () => { + const existing = await ImagePicker.getMediaLibraryPermissionsAsync() + const permission = existing.granted ? existing : await ImagePicker.requestMediaLibraryPermissionsAsync(false) + if (!permission.granted) { + setStatus(permission.canAskAgain ? 'Video access denied.' : 'Open settings to enable video access.') + return + } + const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['videos'], videoMaxDuration: 60 }) + const asset = !result.canceled && result.assets?.[0]?.type === 'video' ? result.assets[0] : null + setVideoUri(asset?.uri ?? null) + setStatus(asset ? `Selected ${Math.round((asset.duration ?? 0) / 1000)}s video.` : 'No video selected.') + } + + return ( + + Video picker + {status} + {videoUri ?? 'No video uri'} + Choose video + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml new file mode 100644 index 00000000..db8d73fd --- /dev/null +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: permission-checked-before-picker + description: "Must call getMediaLibraryPermissionsAsync/requestMediaLibraryPermissionsAsync before launching the picker." + - id: request-not-on-mount + description: "Must request media-library permission from a user action, not on initial mount." + - id: current-video-media-type + description: "Must use mediaTypes: [\"videos\"] or \"videos\" instead of deprecated MediaTypeOptions.Videos." + - id: handles-limited-or-denied + description: "Must render a deterministic UI for denied or limited media access and avoid assuming full-library access." + - id: video-asset-guard + description: "Must verify the selected asset exists and is a video before reading uri/duration fields." diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx new file mode 100644 index 00000000..8d53609d --- /dev/null +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Location geocode guard + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md new file mode 100644 index 00000000..34960b50 --- /dev/null +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md @@ -0,0 +1 @@ +Implement a foreground location flow that requests permission on demand, guards geocoding behind granted foreground access, and handles empty reverse-geocode results without crashing. diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx new file mode 100644 index 00000000..01d4ff81 --- /dev/null +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx @@ -0,0 +1,68 @@ +import * as Location from 'expo-location' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [summary, setSummary] = useState('Location not loaded.') + + const locate = async () => { + const permission = await Location.requestForegroundPermissionsAsync() + if (!permission.granted) { + setSummary('Foreground location permission denied.') + return + } + const position = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced }) + const [place] = await Location.reverseGeocodeAsync(position.coords) + setSummary(place ? [place.city, place.region, place.country].filter(Boolean).join(', ') : 'Coordinates found, address unavailable.') + } + + return ( + + Location lookup + {summary} + Use current location + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/requirements.yaml b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/requirements.yaml new file mode 100644 index 00000000..13d5b38a --- /dev/null +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: foreground-permission-before-location + description: "Must call requestForegroundPermissionsAsync before getCurrentPositionAsync when permission is not already granted." + - id: request-on-user-action + description: "Must request location permission from a user-triggered action." + - id: reverse-geocode-after-coordinate + description: "Must call reverseGeocodeAsync only after a valid coordinate is available." + - id: empty-geocode-result-guard + description: "Must handle an empty reverseGeocodeAsync result array with fallback text." + - id: accuracy-explicit + description: "Must pass an explicit Location.Accuracy value to getCurrentPositionAsync." diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx new file mode 100644 index 00000000..46d20e68 --- /dev/null +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Background location permission order + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md new file mode 100644 index 00000000..0b792fe7 --- /dev/null +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md @@ -0,0 +1 @@ +Create a background-location opt-in screen. It must ask for foreground permission before background permission, register a TaskManager task once, and avoid starting updates until both permissions are granted. diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx new file mode 100644 index 00000000..b5810774 --- /dev/null +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx @@ -0,0 +1,61 @@ +import * as Location from 'expo-location' +import * as TaskManager from 'expo-task-manager' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +const TASK_NAME = 'background-location-audit' + +TaskManager.defineTask(TASK_NAME, async ({ data, error }) => { + if (error) return + console.log('background-location', data) +}) + +export default function App() { + const [status, setStatus] = useState('Background tracking is off.') + + const start = async () => { + const foreground = await Location.requestForegroundPermissionsAsync() + if (!foreground.granted) { + setStatus('Foreground permission is required first.') + return + } + const background = await Location.requestBackgroundPermissionsAsync() + if (!background.granted) { + setStatus('Background permission denied.') + return + } + const alreadyStarted = await Location.hasStartedLocationUpdatesAsync(TASK_NAME) + if (!alreadyStarted) { + await Location.startLocationUpdatesAsync(TASK_NAME, { + accuracy: Location.Accuracy.Balanced, + distanceInterval: 100, + pausesUpdatesAutomatically: true, + }) + } + setStatus('Background tracking is active.') + } + + const stop = async () => { + if (await Location.hasStartedLocationUpdatesAsync(TASK_NAME)) { + await Location.stopLocationUpdatesAsync(TASK_NAME) + } + setStatus('Background tracking is off.') + } + + return ( + + Background location + {status} + Enable + Disable + + ) +} + +const styles = StyleSheet.create({ + action: { backgroundColor: '#111827', borderRadius: 10, padding: 12 }, + actionText: { color: '#fff', fontWeight: '600' }, + screen: { backgroundColor: '#fff', flex: 1, padding: 20, rowGap: 12 }, + subtitle: { color: '#4b5563' }, + title: { color: '#111827', fontSize: 20, fontWeight: '700' }, +}) diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/requirements.yaml b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/requirements.yaml new file mode 100644 index 00000000..78f6b6b4 --- /dev/null +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: task-defined-at-module-scope + description: "Must define the TaskManager background task at module scope rather than inside the component render body." + - id: foreground-before-background + description: "Must request foreground location permission and verify it is granted before requesting background permission." + - id: background-start-gated + description: "Must call startLocationUpdatesAsync only after background permission is granted." + - id: no-duplicate-start + description: "Must check hasStartedLocationUpdatesAsync or equivalent state to avoid starting duplicate background updates." + - id: stop-background-updates-action + description: "Must provide a user action that calls stopLocationUpdatesAsync for the same task name." diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx new file mode 100644 index 00000000..85fc4b00 --- /dev/null +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Location accuracy authorization + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md new file mode 100644 index 00000000..c3e1c457 --- /dev/null +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md @@ -0,0 +1 @@ +Build a foreground-location status panel that distinguishes permission status from accuracy/authorization details and degrades gracefully when exact accuracy is unavailable. diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx new file mode 100644 index 00000000..5b343a96 --- /dev/null +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx @@ -0,0 +1,71 @@ +import * as Location from 'expo-location' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [permission, setPermission] = useState(null) + const [message, setMessage] = useState('Check location accuracy.') + + const refresh = async () => { + const nextPermission = await Location.requestForegroundPermissionsAsync() + setPermission(nextPermission) + if (!nextPermission.granted) { + setMessage('Location permission denied.') + return + } + const accuracy = nextPermission.android?.accuracy ?? nextPermission.ios?.scope ?? 'unknown' + const position = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced }) + setMessage(`Accuracy: ${accuracy}; lat ${position.coords.latitude.toFixed(3)}`) + } + + return ( + + Accuracy status + {message} + Refresh + {permission?.canAskAgain === false ? Linking.openSettings()} style={styles.action}>Open settings : null} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml new file mode 100644 index 00000000..7cbfad3f --- /dev/null +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-location-permission-details + description: "Must inspect platform permission details such as permission.ios?.scope or permission.android?.accuracy when present." + - id: does-not-assume-precise-location + description: "Must not assume granted permission implies precise/exact location accuracy." + - id: fallback-for-approximate + description: "Must render a specific approximate-location fallback or explanation." + - id: explicit-location-options + description: "Must use explicit getCurrentPositionAsync accuracy options." + - id: settings-recovery-for-blocked + description: "Must offer Linking.openSettings() when permission canAskAgain is false." diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx new file mode 100644 index 00000000..581b565f --- /dev/null +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Notifications channel and token + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md new file mode 100644 index 00000000..b9b96f6e --- /dev/null +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md @@ -0,0 +1 @@ +Implement push-notification registration that creates an Android channel before requesting an Expo push token, handles permission denial, and passes an EAS projectId when requesting the token. diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx new file mode 100644 index 00000000..13419d92 --- /dev/null +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx @@ -0,0 +1,83 @@ +import Constants from 'expo-constants' +import * as Notifications from 'expo-notifications' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [status, setStatus] = useState('Not registered.') + + const register = async () => { + try { + if (Platform.OS === 'android') { + await Notifications.setNotificationChannelAsync('default', { + importance: Notifications.AndroidImportance.MAX, + name: 'Default', + }) + } + const permission = await Notifications.requestPermissionsAsync() + if (!permission.granted) { + setStatus('Notification permission denied.') + return + } + const projectId = Constants.easConfig?.projectId ?? Constants.expoConfig?.extra?.eas?.projectId + if (!projectId) { + setStatus('Missing EAS project id.') + return + } + const token = await Notifications.getExpoPushTokenAsync({ projectId }) + setStatus(token.data) + } catch (error) { + setStatus(error instanceof Error ? error.message : 'Token registration failed.') + } + } + + return ( + + Push token + {status} + Register + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/requirements.yaml b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/requirements.yaml new file mode 100644 index 00000000..a8a59691 --- /dev/null +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: android-channel-before-token + description: "Must call Notifications.setNotificationChannelAsync on Android before getExpoPushTokenAsync." + - id: permission-gated-token + description: "Must request/check notification permission and avoid getExpoPushTokenAsync when permission is not granted." + - id: project-id-passed + description: "Must pass a projectId option to getExpoPushTokenAsync." + - id: token-error-state + description: "Must catch token registration errors and render a deterministic error state." + - id: no-deprecated-notification-field + description: "Must not rely on the removed top-level app config notification field for runtime channel setup." diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx new file mode 100644 index 00000000..2a22acd9 --- /dev/null +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Notifications listener cleanup + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md new file mode 100644 index 00000000..7ab6777c --- /dev/null +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md @@ -0,0 +1 @@ +Create a notification inbox component that subscribes to foreground notifications and response taps, updates local state, and cleans up every subscription on unmount. diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx new file mode 100644 index 00000000..dc10bd9a --- /dev/null +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx @@ -0,0 +1,69 @@ +import * as Notifications from 'expo-notifications' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [events, setEvents] = useState([]) + + useEffect(() => { + const received = Notifications.addNotificationReceivedListener((notification) => { + setEvents((items) => [notification.request.identifier, ...items]) + }) + const responses = Notifications.addNotificationResponseReceivedListener((response) => { + setEvents((items) => [`tap:${response.notification.request.identifier}`, ...items]) + }) + return () => { + received.remove() + responses.remove() + } + }, []) + + return ( + + Notification inbox + {events.map((event) => {event})} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml new file mode 100644 index 00000000..faeab568 --- /dev/null +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: received-listener-registered + description: "Must register addNotificationReceivedListener in a mount effect." + - id: response-listener-registered + description: "Must register addNotificationResponseReceivedListener in the same component lifecycle." + - id: subscriptions-removed + description: "Must call remove() on every notification subscription in the effect cleanup." + - id: state-update-from-listeners + description: "Must update visible local state from both received notification and response listener payloads." + - id: no-remove-all-listeners + description: "Must not use removeAllListeners as cleanup for component-scoped subscriptions." diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx new file mode 100644 index 00000000..bc88cdff --- /dev/null +++ b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Notifications project id guard + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md new file mode 100644 index 00000000..e430e9d8 --- /dev/null +++ b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md @@ -0,0 +1 @@ +Build a push-token helper that resolves projectId from Expo Constants, handles missing projectId in Expo Go or local builds, and never calls getExpoPushTokenAsync with an undefined projectId. diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx new file mode 100644 index 00000000..8e7d17c8 --- /dev/null +++ b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx @@ -0,0 +1,73 @@ +import Constants from 'expo-constants' +import * as Notifications from 'expo-notifications' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('Ready.') + + const getToken = async () => { + const projectId = Constants.easConfig?.projectId ?? Constants.expoConfig?.extra?.eas?.projectId + if (!projectId) { + setMessage('Push tokens require an EAS project id; configure extra.eas.projectId for this build.') + return + } + const permission = await Notifications.requestPermissionsAsync() + if (!permission.granted) { + setMessage('Notification permission denied.') + return + } + const token = await Notifications.getExpoPushTokenAsync({ projectId }) + setMessage(token.data) + } + + return ( + + Project token + {message} + Get token + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml new file mode 100644 index 00000000..45409b32 --- /dev/null +++ b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: project-id-from-constants + description: "Must derive projectId from Constants.easConfig?.projectId or Constants.expoConfig?.extra?.eas?.projectId." + - id: undefined-project-id-guard + description: "Must branch before getExpoPushTokenAsync when projectId is missing." + - id: expo-go-or-dev-message + description: "Must render a clear local-development/Expo Go fallback message for missing projectId." + - id: permission-before-token + description: "Must request notification permission before requesting the push token." + - id: token-request-passes-object + description: "Must call getExpoPushTokenAsync with an options object containing projectId." diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx new file mode 100644 index 00000000..ad6425f5 --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Notifications config + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts new file mode 100644 index 00000000..b67f76a0 --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts @@ -0,0 +1,9 @@ +export default { + expo: { + name: 'notification-config-audit', + slug: 'notification-config-audit', + notification: { + icon: './assets/notification.png', + }, + }, +} diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md new file mode 100644 index 00000000..5cf61341 --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md @@ -0,0 +1 @@ +Move notification native configuration into the expo-notifications config plugin. Do not use the removed top-level notification field in app config. diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx new file mode 100644 index 00000000..ad6425f5 --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Notifications config + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts new file mode 100644 index 00000000..c89e270f --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts @@ -0,0 +1,17 @@ +export default { + expo: { + name: 'notification-config-audit', + slug: 'notification-config-audit', + plugins: [ + [ + 'expo-notifications', + { + color: '#111827', + defaultChannel: 'default', + enableBackgroundRemoteNotifications: true, + icon: './assets/notification.png', + }, + ], + ], + }, +} diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml new file mode 100644 index 00000000..b698d4c7 --- /dev/null +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml @@ -0,0 +1,16 @@ +version: 1 +inputs: + files: + - app/App.tsx + - app/app.config.ts +requirements: + - id: uses-expo-notifications-plugin + description: "Must configure expo-notifications through the plugins array in app.config.ts/app.json." + - id: removes-top-level-notification + description: "Must not leave a top-level expo.notification object in app config." + - id: preserves-icon-color-channel + description: "Must preserve native notification icon/color/default channel configuration inside the plugin options." + - id: background-remote-plugin-option + description: "Must configure enableBackgroundRemoteNotifications in plugin options when background remote notifications are required." + - id: config-remains-static-export + description: "Must keep app config as a valid exported object or config function." diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx new file mode 100644 index 00000000..1a21020a --- /dev/null +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + FileSystem object API + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md new file mode 100644 index 00000000..8050727b --- /dev/null +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md @@ -0,0 +1 @@ +Implement a cache-backed notes file using the current expo-file-system object API. Create directories idempotently, write text, read text, and avoid root-level legacy functions that throw in SDK 56. diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx new file mode 100644 index 00000000..732205a0 --- /dev/null +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx @@ -0,0 +1,74 @@ +import { Directory, File, Paths } from 'expo-file-system' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const noteFile = useMemo(() => new File(new Directory(Paths.cache, 'notes'), 'daily.txt'), []) + const [text, setText] = useState('No note loaded.') + + const save = async () => { + const dir = new Directory(Paths.cache, 'notes') + dir.create({ idempotent: true, intermediates: true }) + noteFile.write('Expo SDK 56 file-system note') + setText(await noteFile.text()) + } + + const load = async () => { + try { + setText(await noteFile.text()) + } catch { + setText('No note exists yet.') + } + } + + return ( + + File note + {text} + Save + Load + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml new file mode 100644 index 00000000..f6c66312 --- /dev/null +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: imports-file-directory-paths + description: "Must import File, Directory, and Paths from expo-file-system." + - id: creates-directory-idempotently + description: "Must create a Directory under Paths.cache or Paths.document with idempotent/intermediates options." + - id: uses-file-instance-read-write + description: "Must call File instance methods such as write() and text() for read/write operations." + - id: avoids-root-legacy-methods + description: "Must not call root readAsStringAsync/writeAsStringAsync/makeDirectoryAsync from expo-file-system." + - id: handles-read-missing-file + description: "Must handle missing-file or first-run reads with fallback text instead of crashing." diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx new file mode 100644 index 00000000..10bf6563 --- /dev/null +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + FileSystem legacy import boundary + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md new file mode 100644 index 00000000..54881d44 --- /dev/null +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md @@ -0,0 +1 @@ +Repair a file helper that still uses legacy FileSystem method names. Either migrate it to the object API or import legacy methods from expo-file-system/legacy; do not use runtime-throwing root exports. diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx new file mode 100644 index 00000000..f53640bf --- /dev/null +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx @@ -0,0 +1,69 @@ +import { Directory, File, Paths } from 'expo-file-system' +import * as LegacyFileSystem from 'expo-file-system/legacy' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('Ready.') + + const migrate = async () => { + const file = new File(Paths.cache, 'profile.json') + file.write(JSON.stringify({ name: 'Expo' })) + setMessage(await file.text()) + } + + const readLegacyUri = async (uri: string) => { + return LegacyFileSystem.readAsStringAsync(uri) + } + + return ( + + Filesystem migration + {message} + Use object API + void readLegacyUri(new File(new Directory(Paths.cache), 'profile.json').uri)} style={styles.action}>Read legacy uri + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml new file mode 100644 index 00000000..3befc401 --- /dev/null +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: no-root-legacy-import + description: "Must not import readAsStringAsync, writeAsStringAsync, downloadAsync, uploadAsync, getInfoAsync, or makeDirectoryAsync from the root expo-file-system module." + - id: legacy-import-if-needed + description: "Must import old helper methods from expo-file-system/legacy when retaining the legacy method style." + - id: object-api-preferred + description: "Must use File/Directory/Paths from expo-file-system for new read/write code." + - id: documents-runtime-throw-trap + description: "Must make the code path clear enough that root legacy methods are avoided because they throw at runtime in current SDKs." + - id: keeps-uri-boundary-explicit + description: "Must keep file URI/path construction explicit instead of concatenating undefined documentDirectory/cacheDirectory root constants." diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx new file mode 100644 index 00000000..3fc651ed --- /dev/null +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + FileSystem download upload + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md new file mode 100644 index 00000000..de3d0056 --- /dev/null +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md @@ -0,0 +1 @@ +Implement a download-and-upload flow with the current expo-file-system File API. Download into a cache Directory/File destination, expose progress/status, and upload the File as a Blob-compatible value with fetch/FormData. diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx new file mode 100644 index 00000000..d27eef4e --- /dev/null +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx @@ -0,0 +1,71 @@ +import { Directory, File, Paths } from 'expo-file-system' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [status, setStatus] = useState('Idle.') + + const sync = async () => { + try { + const downloads = new Directory(Paths.cache, 'downloads') + downloads.create({ idempotent: true, intermediates: true }) + const file = await File.downloadFileAsync('https://example.com/report.txt', downloads) + const body = new FormData() + body.append('file', file as unknown as Blob) + await fetch('https://example.com/upload', { body, method: 'POST' }) + setStatus(`Uploaded ${file.name}`) + } catch (error) { + setStatus(error instanceof Error ? error.message : 'Sync failed.') + } + } + + return ( + + File sync + {status} + Sync + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml new file mode 100644 index 00000000..23e00448 --- /dev/null +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-file-download-file-async + description: "Must use File.downloadFileAsync with a Directory or File destination from the object API." + - id: destination-directory-created + description: "Must create the destination Directory idempotently before downloading." + - id: upload-uses-fetch-formdata + description: "Must upload using fetch with FormData or another current web-compatible API instead of root uploadAsync." + - id: no-root-download-upload-async + description: "Must not call root FileSystem.downloadAsync or uploadAsync from expo-file-system." + - id: download-error-state + description: "Must catch download/upload errors and render a deterministic failure state." diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx new file mode 100644 index 00000000..e9ac81c9 --- /dev/null +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + MediaLibrary granular write-only + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md new file mode 100644 index 00000000..b8e1c03d --- /dev/null +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md @@ -0,0 +1 @@ +Create a save-to-photos permission flow that requests write-only photo access with Android granular permissions and clearly separates write-only from read-library access. diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx new file mode 100644 index 00000000..c929f6d5 --- /dev/null +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx @@ -0,0 +1,62 @@ +import * as MediaLibrary from 'expo-media-library' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('Ready to save a generated photo.') + + const requestSaveAccess = async () => { + const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) + setMessage(permission.granted ? 'Write-only photo access granted.' : 'Photo save permission denied.') + } + + return ( + + Save access + {message} + Request save access + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml new file mode 100644 index 00000000..525553ab --- /dev/null +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: write-only-permission-request + description: "Must call MediaLibrary.requestPermissionsAsync with writeOnly true for save-only behavior." + - id: granular-photo-permission + description: "Must pass granularPermissions containing photo when requesting photo-only access." + - id: does-not-query-library-with-writeonly + description: "Must not query/read the user library after requesting write-only permission." + - id: permission-plugin-note + description: "Must keep app/config code aligned with any granular permissions requested at runtime." + - id: denied-fallback + description: "Must render a deterministic denied-permission fallback." diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx new file mode 100644 index 00000000..04edf58c --- /dev/null +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + MediaLibrary Asset.create + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md new file mode 100644 index 00000000..49722e6c --- /dev/null +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md @@ -0,0 +1 @@ +Implement a generated-image save flow using expo-media-library current class APIs. Create an Asset from a file path and optionally add it to an Album without using stale root createAssetAsync. diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx new file mode 100644 index 00000000..27fb0201 --- /dev/null +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx @@ -0,0 +1,72 @@ +import { File, Paths } from 'expo-file-system' +import * as MediaLibrary from 'expo-media-library' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('No asset saved.') + + const save = async () => { + const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) + if (!permission.granted) { + setMessage('Cannot save without photo permission.') + return + } + const file = new File(Paths.cache, 'generated-photo.txt') + file.write('placeholder-image-bytes') + const asset = await MediaLibrary.Asset.create(file.uri) + const album = (await MediaLibrary.Album.get('Exports')) ?? await MediaLibrary.Album.create('Exports', [asset], false) + await album.add(asset) + setMessage(await asset.getFilename()) + } + + return ( + + Media asset + {message} + Save asset + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml new file mode 100644 index 00000000..1e4b8f01 --- /dev/null +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-asset-create + description: "Must use MediaLibrary.Asset.create or the exported Asset class create() method for new assets." + - id: avoids-root-createassetasync + description: "Must not call root MediaLibrary.createAssetAsync from expo-media-library." + - id: album-current-api + description: "Must use Album.get/Album.create or album.add for album management instead of stale createAlbumAsync helpers." + - id: permission-before-asset-create + description: "Must request/check media-library permission before creating the asset." + - id: file-uri-validated + description: "Must validate that a file path/URI exists before creating the asset." diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx new file mode 100644 index 00000000..fade8543 --- /dev/null +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Calendar current API + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md new file mode 100644 index 00000000..e9b09d60 --- /dev/null +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md @@ -0,0 +1 @@ +Build a calendar-event creation screen that uses the current expo-calendar API surface, handles permission denial, and avoids legacy Async helpers that now live behind legacy warnings. diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx new file mode 100644 index 00000000..4e908c19 --- /dev/null +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx @@ -0,0 +1,77 @@ +import * as Calendar from 'expo-calendar' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('No event created.') + + const create = async () => { + const permission = await Calendar.requestCalendarPermissions() + if (!permission.granted) { + setMessage('Calendar permission denied.') + return + } + const calendars = await Calendar.getCalendars(Calendar.EntityTypes.EVENT) + const calendar = calendars.find((item) => item.allowsModifications) + if (!calendar) { + setMessage('No writable calendar available.') + return + } + const event = await calendar.createEvent({ + endDate: new Date(Date.now() + 60 * 60 * 1000), + startDate: new Date(), + title: 'Expo planning', + }) + setMessage(event.id) + } + + return ( + + Calendar + {message} + Create event + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml new file mode 100644 index 00000000..c1625080 --- /dev/null +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-request-calendar-permissions + description: "Must use Calendar.requestCalendarPermissions instead of requestCalendarPermissionsAsync from the root module." + - id: uses-get-calendars-current + description: "Must use Calendar.getCalendars instead of getCalendarsAsync from the root module." + - id: uses-calendar-instance-create-event + description: "Must create events through a calendar object createEvent method rather than root createEventAsync." + - id: permission-denied-fallback + description: "Must render a deterministic fallback when calendar permission is denied." + - id: selects-writable-calendar + description: "Must choose a writable calendar or handle the absence of one explicitly." diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx new file mode 100644 index 00000000..f81d2132 --- /dev/null +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Contacts fields query + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md new file mode 100644 index 00000000..e474a6ab --- /dev/null +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md @@ -0,0 +1 @@ +Implement a contacts lookup screen that requests contacts permission on demand, queries only the fields it renders, and handles empty contact lists and denied permission. diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx new file mode 100644 index 00000000..bda1d727 --- /dev/null +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx @@ -0,0 +1,82 @@ +import * as Contacts from 'expo-contacts' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [contacts, setContacts] = useState< + Array<{ fullName?: string | null; id: string }> + >([]) + const [message, setMessage] = useState('Contacts not loaded.') + + const load = async () => { + const permission = await Contacts.requestPermissionsAsync() + if (!permission.granted) { + setMessage('Contacts permission denied.') + return + } + const result = await Contacts.Contact.getAllDetails( + [ + Contacts.ContactField.FULL_NAME, + Contacts.ContactField.EMAILS, + Contacts.ContactField.IMAGE, + ], + { limit: 20 } + ) + setContacts(result.map((contact) => ({ + fullName: contact.fullName, + id: contact.id, + }))) + setMessage(result.length ? 'Contacts loaded.' : 'No contacts available.') + } + + return ( + + Contacts + {message} + {contacts.map((contact) => {contact.fullName ?? 'Unnamed contact'})} + Load contacts + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml new file mode 100644 index 00000000..917f8d70 --- /dev/null +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: permission-before-query + description: "Must request contacts permission before calling Contacts.Contact.getAllDetails or another current Contact class query API." + - id: field-allowlist + description: "Must pass a ContactField allowlist that includes only the rendered fields, such as FULL_NAME, EMAILS, and IMAGE." + - id: empty-list-fallback + description: "Must handle an empty data array with deterministic fallback UI." + - id: no-query-on-mount-permission-prompt + description: "Must not prompt for contacts permission on initial mount." + - id: config-plugin-fields-mentioned + description: "Must include or preserve contacts permission strings in app config when adding config files for the eval." diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx new file mode 100644 index 00000000..219f15c7 --- /dev/null +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Audio player lifecycle + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md new file mode 100644 index 00000000..c4289bad --- /dev/null +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md @@ -0,0 +1 @@ +Build an audio preview component with expo-audio, not expo-av. Use the managed player hook, subscribe to player status, configure audio mode deliberately, and release/stop playback on lifecycle changes. diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx new file mode 100644 index 00000000..5e43ade1 --- /dev/null +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx @@ -0,0 +1,70 @@ +import { setAudioModeAsync, useAudioPlayer, useAudioPlayerStatus } from 'expo-audio' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const player = useAudioPlayer('https://example.com/preview.mp3', { updateInterval: 250 }) + const status = useAudioPlayerStatus(player) + + useEffect(() => { + void setAudioModeAsync({ playsInSilentMode: true }) + const sub = AppState.addEventListener('change', (state) => { + if (state !== 'active') player.pause() + }) + return () => { + player.pause() + sub.remove() + } + }, [player]) + + return ( + + Audio preview + {status.playing ? 'Playing' : 'Paused'} + player.play()} style={styles.action}>Play + player.pause()} style={styles.action}>Pause + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml new file mode 100644 index 00000000..380c52dd --- /dev/null +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-expo-audio + description: "Must import playback APIs from expo-audio and not from expo-av." + - id: uses-managed-player-hook + description: "Must use useAudioPlayer for component-managed player lifecycle." + - id: uses-player-status-hook + description: "Must use useAudioPlayerStatus or an equivalent current status subscription for UI state." + - id: audio-mode-explicit + description: "Must call setAudioModeAsync with deliberate playback/interruption options." + - id: pause-or-stop-on-background + description: "Must pause playback when AppState leaves active or the component unmounts." diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx b/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx new file mode 100644 index 00000000..c086a53f --- /dev/null +++ b/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Video player view + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md b/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md new file mode 100644 index 00000000..458af2eb --- /dev/null +++ b/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md @@ -0,0 +1 @@ +Build a video player using expo-video. Create the player with useVideoPlayer, render it with VideoView, avoid expo-av Video, and clean up or pause playback when the component loses visibility. diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx new file mode 100644 index 00000000..d5b21b57 --- /dev/null +++ b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx @@ -0,0 +1,70 @@ +import { useVideoPlayer, VideoView } from 'expo-video' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const player = useVideoPlayer('https://example.com/demo.mp4', (nextPlayer) => { + nextPlayer.loop = true + nextPlayer.muted = true + }) + + useEffect(() => { + const sub = AppState.addEventListener('change', (state) => { + if (state !== 'active') player.pause() + }) + return () => { + player.pause() + sub.remove() + } + }, [player]) + + return ( + + Video + + player.play()} style={styles.action}>Play + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml b/evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml new file mode 100644 index 00000000..45e9f6cb --- /dev/null +++ b/evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-expo-video + description: "Must import VideoView and useVideoPlayer from expo-video." + - id: no-expo-av-video + description: "Must not import Video or playback APIs from expo-av." + - id: player-created-with-hook + description: "Must create the player with useVideoPlayer and configure looping/muted/playback in the setup callback or player API." + - id: videoview-receives-player + description: "Must pass the player object to VideoView." + - id: visibility-lifecycle + description: "Must pause or avoid autoplay when the app is backgrounded or the view is not active." diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx new file mode 100644 index 00000000..dbbae2ad --- /dev/null +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Video thumbnail replacement + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md new file mode 100644 index 00000000..c5f6afa9 --- /dev/null +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md @@ -0,0 +1 @@ +Replace a stale expo-video-thumbnails helper with expo-video thumbnail generation. Generate thumbnails from the VideoPlayer, handle empty output, and avoid importing expo-video-thumbnails. diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx new file mode 100644 index 00000000..5f91608d --- /dev/null +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx @@ -0,0 +1,67 @@ +import { Image } from 'expo-image' +import { useVideoPlayer, type VideoThumbnail } from 'expo-video' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const player = useVideoPlayer('https://example.com/demo.mp4') + const [thumbnail, setThumbnail] = useState(null) + const [message, setMessage] = useState('No thumbnail.') + + const generate = async () => { + const thumbnails = await player.generateThumbnailsAsync([1, 3], { maxWidth: 480 }) + const first = thumbnails[0] + setThumbnail(first ?? null) + setMessage(first ? `Generated at ${first.actualTime}s` : 'Thumbnail unavailable.') + } + + return ( + + Thumbnail + {thumbnail ? : {message}} + Generate + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml new file mode 100644 index 00000000..c2d6f0cd --- /dev/null +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: no-expo-video-thumbnails + description: "Must not import or call expo-video-thumbnails." + - id: uses-video-player-thumbnail-api + description: "Must use the expo-video player thumbnail API such as generateThumbnailsAsync." + - id: handles-empty-thumbnail-array + description: "Must handle an empty thumbnails array with fallback UI." + - id: thumbnail-time-explicit + description: "Must request thumbnails at explicit second offsets." + - id: thumbnail-image-rendered + description: "Must render the generated thumbnail image/URI or a deterministic fallback." diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx new file mode 100644 index 00000000..16bcd0d8 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Updates progress reload screen + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md new file mode 100644 index 00000000..22e4ade4 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md @@ -0,0 +1 @@ +Create an update-ready screen with expo-updates. Use useUpdates for state/progress, show a reload screen while applying a downloaded update, and avoid unsafe JS assumptions after reloadAsync resolves. diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx new file mode 100644 index 00000000..42d90cd9 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx @@ -0,0 +1,72 @@ +import * as Updates from 'expo-updates' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const updateState = Updates.useUpdates() + const [message, setMessage] = useState('Check for updates.') + + const apply = async () => { + if (!updateState.isUpdatePending) { + setMessage(updateState.downloadError?.message ?? 'No downloaded update to apply.') + return + } + await Updates.reloadAsync({ + reloadScreenOptions: { + backgroundColor: '#111827', + fade: true, + }, + }) + } + + return ( + + Updates + {updateState.isDownloading ? `Downloading ${Math.round((updateState.downloadProgress ?? 0) * 100)}%` : message} + {updateState.currentlyRunning.isEmbeddedLaunch ? 'Embedded launch' : 'Update launch'} + Apply update + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml new file mode 100644 index 00000000..2b0876a7 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-useupdates-state + description: "Must use Updates.useUpdates() to read isDownloading, downloadProgress, isUpdateAvailable, isUpdatePending, and currentlyRunning state." + - id: download-progress-rendered + description: "Must render downloadProgress or a deterministic progress state while downloading." + - id: reload-screen-options + description: "Must call Updates.reloadAsync with reloadScreenOptions when applying a downloaded update." + - id: no-post-reload-assumption + description: "Must not update React state after awaiting reloadAsync as if execution will reliably continue." + - id: handles-disabled-or-error + description: "Must render a fallback for unavailable updates or download errors." diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx b/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx new file mode 100644 index 00000000..0cbae076 --- /dev/null +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Updates request headers + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md b/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md new file mode 100644 index 00000000..b8b5f83f --- /dev/null +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md @@ -0,0 +1 @@ +Implement a release-channel switcher that updates expo-updates request headers at runtime, clears overrides when returning to default, and avoids persisting stale cohort headers across sessions. diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx b/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx new file mode 100644 index 00000000..fa825f63 --- /dev/null +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx @@ -0,0 +1,66 @@ +import * as Updates from 'expo-updates' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [cohort, setCohort] = useState<'default' | 'beta'>('default') + const [message, setMessage] = useState('Default updates.') + + const select = async (next: 'default' | 'beta') => { + setCohort(next) + Updates.setUpdateRequestHeadersOverride(next === 'default' ? null : { 'expo-channel-name': 'beta' }) + const result = await Updates.checkForUpdateAsync() + setMessage(result.isAvailable ? 'Update available for cohort.' : 'No update for cohort.') + } + + return ( + + Update cohort + {cohort}: {message} + select('beta')} style={styles.action}>Beta + select('default')} style={styles.action}>Default + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml b/evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml new file mode 100644 index 00000000..7f5bed62 --- /dev/null +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-header-override-api + description: "Must call Updates.setUpdateRequestHeadersOverride with a record or null." + - id: clear-override-path + description: "Must provide a default path that calls setUpdateRequestHeadersOverride(null)." + - id: no-secret-header-values + description: "Must not hardcode secrets or authorization tokens in update request headers." + - id: check-after-header-change + description: "Must trigger or expose an update check/fetch flow after changing headers." + - id: visible-selected-cohort + description: "Must render the active cohort/header selection so behavior is auditable." diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx new file mode 100644 index 00000000..eab9b9aa --- /dev/null +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Status and navigation bars + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md new file mode 100644 index 00000000..75fc49e8 --- /dev/null +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md @@ -0,0 +1 @@ +Build a screen-level system UI controller using current expo-status-bar, expo-navigation-bar, and expo-glass-effect APIs. Prefer component/namespace APIs, gate Liquid Glass usage with availability checks, and clean up listeners. diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx new file mode 100644 index 00000000..b38ba53d --- /dev/null +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx @@ -0,0 +1,82 @@ +import { GlassView, isGlassEffectAPIAvailable } from 'expo-glass-effect' +import { NavigationBar, addVisibilityListener } from 'expo-navigation-bar' +import { StatusBar } from 'expo-status-bar' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [visible, setVisible] = useState('unknown') + const canUseGlass = isGlassEffectAPIAvailable() + + useEffect(() => { + StatusBar.setStyle('light', true) + if (Platform.OS !== 'android') return () => StatusBar.setStyle('auto', true) + NavigationBar.setStyle('dark') + const sub = addVisibilityListener((event) => setVisible(event.visibility)) + return () => { + sub.remove() + StatusBar.setStyle('auto', true) + NavigationBar.setStyle('auto') + } + }, []) + + return ( + + + {Platform.OS === 'android' ? : null} + System bars + Navigation bar: {visible} + {canUseGlass ? ( + + Liquid Glass controls available + + ) : ( + + Liquid Glass fallback + + )} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml new file mode 100644 index 00000000..582cbc95 --- /dev/null +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml @@ -0,0 +1,19 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-statusbar-component-or-namespace + description: "Must use StatusBar component or StatusBar.setStyle/setHidden from expo-status-bar rather than deprecated setStatusBarStyle/setStatusBarHidden helpers." + - id: uses-navigationbar-component-or-namespace + description: "Must use NavigationBar component or NavigationBar.setStyle from expo-navigation-bar rather than deprecated root setStyle." + - id: visibility-listener-cleanup + description: "Must remove addVisibilityListener subscription on cleanup when listening for navigation bar visibility changes." + - id: platform-android-guard + description: "Must guard Android-only navigation bar behavior with Platform.OS === \"android\" or a safe cross-platform component path." + - id: restores-bars-on-unmount + description: "Must restore default bar visibility/style on unmount or when leaving the screen." + - id: glass-effect-current-package + description: "Must import GlassView or GlassContainer from expo-glass-effect, not from @expo/ui." + - id: glass-effect-availability-guard + description: "Must check isGlassEffectAPIAvailable() or isLiquidGlassAvailable() before rendering Liquid Glass UI and render a deterministic fallback otherwise." diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx new file mode 100644 index 00000000..d075ec12 --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Build properties + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts new file mode 100644 index 00000000..a3edb600 --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts @@ -0,0 +1,16 @@ +export default { + expo: { + name: 'build-properties-audit', + slug: 'build-properties-audit', + plugins: [ + [ + 'expo-build-properties', + { + ios: { + useFrameworks: 'static', + }, + }, + ], + ], + }, +} diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md new file mode 100644 index 00000000..af7729e5 --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md @@ -0,0 +1 @@ +Configure expo-build-properties for an SDK 56 project that opts into iOS precompiled React Native dependencies and Android build properties without using stale property names. diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx new file mode 100644 index 00000000..d075ec12 --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Build properties + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts new file mode 100644 index 00000000..d19cd3af --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts @@ -0,0 +1,23 @@ +export default { + expo: { + name: 'build-properties-audit', + slug: 'build-properties-audit', + plugins: [ + [ + 'expo-build-properties', + { + android: { + compileSdkVersion: 36, + targetSdkVersion: 36, + }, + ios: { + buildReactNativeFromSource: false, + ccacheEnabled: true, + forceStaticLinking: ['RNFBApp'], + useFrameworks: 'static', + }, + }, + ], + ], + }, +} diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml new file mode 100644 index 00000000..35981786 --- /dev/null +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml @@ -0,0 +1,16 @@ +version: 1 +inputs: + files: + - app/App.tsx + - app/app.config.ts +requirements: + - id: uses-expo-build-properties-plugin + description: "Must configure expo-build-properties in the app config plugins array." + - id: ios-precompiled-rn-enabled + description: "Must opt into the SDK 56-era precompiled React Native dependency path with buildReactNativeFromSource: false or the current equivalent." + - id: keeps-static-frameworks-intent + description: "Must preserve useFrameworks: \"static\" when the project requires static frameworks." + - id: android-sdk-values-current + description: "Must set Android compile/target SDK values compatible with SDK 56." + - id: no-stale-property-names + description: "Must not use removed or guessed build-properties keys for precompiled headers." diff --git a/evals/expo-sdk/README.md b/evals/expo-sdk/README.md index b6e411e7..133f087d 100644 --- a/evals/expo-sdk/README.md +++ b/evals/expo-sdk/README.md @@ -1,30 +1,43 @@ -# expo-sdk eval research (feature-first) +# Expo SDK eval category ## category overview -This document is the reference for Expo SDK focused evals under `evals/expo-sdk/`. +Expo SDK evals cover current SDK 56 behavior across Expo capability modules, permissions, app lifecycle, native config plugins, media APIs, system UI, updates, and SDK split/replacement APIs. ## library baseline and naming -- Expo SDK capability modules baseline: `expo-camera`, `expo-image-picker`, `expo-location`, `expo-notifications` -- Category convention: eval IDs in this folder should start from `01-...` and stay ordered by scope complexity +- Baseline: Expo SDK 56 with React 19.2 and React Native 0.85 in the testbench. +- Capability packages: expo-camera, expo-image-picker, expo-location, expo-notifications, expo-file-system, expo-media-library, expo-calendar, expo-contacts, expo-audio, expo-video, expo-updates, expo-status-bar, expo-navigation-bar, expo-build-properties, expo-glass-effect. +- Eval IDs start with two digits and the `rn-expo-` prefix. ## best practices ### official best-practice sources -- [Expo permissions guide](https://docs.expo.dev/guides/permissions/) -- [Expo Camera docs](https://docs.expo.dev/versions/latest/sdk/camera/) -- [Expo ImagePicker docs](https://docs.expo.dev/versions/latest/sdk/imagepicker/) -- [Expo Location docs](https://docs.expo.dev/versions/latest/sdk/location/) -- [Expo Notifications docs](https://docs.expo.dev/versions/latest/sdk/notifications/) -- [Expo push notifications setup](https://docs.expo.dev/push-notifications/push-notifications-setup/) -- [Expo SDK changelog](https://expo.dev/changelog) +- Expo SDK 56 changelog: https://expo.dev/changelog/sdk-56 +- Expo SDK 55 changelog: https://expo.dev/changelog/sdk-55 +- Expo SDK 54 changelog: https://expo.dev/changelog/sdk-54 +- Expo permissions guide: https://docs.expo.dev/guides/permissions/ +- Expo Camera: https://docs.expo.dev/versions/latest/sdk/camera/ +- Expo ImagePicker: https://docs.expo.dev/versions/latest/sdk/imagepicker/ +- Expo Location: https://docs.expo.dev/versions/latest/sdk/location/ +- Expo Notifications: https://docs.expo.dev/versions/latest/sdk/notifications/ +- Expo FileSystem: https://docs.expo.dev/versions/latest/sdk/filesystem/ +- Expo MediaLibrary: https://docs.expo.dev/versions/latest/sdk/media-library/ +- Expo Calendar: https://docs.expo.dev/versions/latest/sdk/calendar/ +- Expo Audio: https://docs.expo.dev/versions/latest/sdk/audio/ +- Expo Video: https://docs.expo.dev/versions/latest/sdk/video/ +- Expo Updates: https://docs.expo.dev/versions/latest/sdk/updates/ +- Expo StatusBar: https://docs.expo.dev/versions/latest/sdk/status-bar/ +- Expo NavigationBar: https://docs.expo.dev/versions/latest/sdk/navigation-bar/ +- Expo BuildProperties: https://docs.expo.dev/versions/latest/sdk/build-properties/ ### best-practice inventory -- `E1`: request capability permissions only after explicit user intent; avoid auto-requesting on first render. -- `E2`: model `undetermined`, `granted`, denied-retry, and blocked/settings-recovery states explicitly. -- `E3`: gate SDK feature rendering and actions behind confirmed granted permission. -- `E4`: refresh permission/capability state on app foreground to reflect system-settings changes. -- `E5`: provide deterministic degraded UI when permission or hardware availability blocks feature usage. +- E1: Request sensitive permissions only after explicit user intent. +- E2: Model denied, blocked, limited, and settings-recovery states explicitly. +- E3: Gate native views and native actions behind granted permissions and app lifecycle visibility. +- E4: Use SDK 56 replacement packages: expo-audio and expo-video instead of expo-av, expo-video thumbnails instead of expo-video-thumbnails. +- E5: Use current object/class APIs where SDK 56 root legacy methods now warn or throw, especially FileSystem, Calendar, and MediaLibrary. +- E6: Keep runtime behavior and app config aligned for notifications, media permissions, background tasks, updates, and build properties. +- E7: Treat expo-glass-effect as an Expo SDK package, gate Liquid Glass rendering with availability checks, and keep it out of @expo/ui evals. diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx new file mode 100644 index 00000000..a89cc532 --- /dev/null +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI universal Host + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md new file mode 100644 index 00000000..6cac575e --- /dev/null +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md @@ -0,0 +1 @@ +Build a universal Expo UI screen with Host as the native UI root and React Native content only where it is intentionally hosted. diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx new file mode 100644 index 00000000..979e246e --- /dev/null +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx @@ -0,0 +1,55 @@ +import { Button, Host, RNHostView, Text as UIText } from '@expo/ui' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Native settings + + React Native child intentionally hosted + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml b/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml new file mode 100644 index 00000000..fa78ff2d --- /dev/null +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: imports-universal-host + description: "Must import Host from @expo/ui." + - id: host-root-wraps-native-ui + description: "Must render Expo UI native components inside a Host root." + - id: rn-host-view-only-for-rn-children + description: "Must use RNHostView only when intentionally hosting React Native children inside native UI." + - id: no-glass-effect + description: "Must not import expo-glass-effect or treat GlassEffect as part of @expo/ui." diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx new file mode 100644 index 00000000..3fef911c --- /dev/null +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI layout controls + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md new file mode 100644 index 00000000..5bf5cabd --- /dev/null +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md @@ -0,0 +1 @@ +Build a settings panel with Expo UI universal Column/Row/Text/Button/Switch controls and controlled state. diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx new file mode 100644 index 00000000..4e9102bc --- /dev/null +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx @@ -0,0 +1,58 @@ +import { Button, Column, Host, Row, Switch, Text as UIText } from '@expo/ui' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [enabled, setEnabled] = useState(false) + return ( + + + Preferences + Sync + + + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml new file mode 100644 index 00000000..795f3d47 --- /dev/null +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-universal-layout-primitives + description: "Must use @expo/ui universal layout/control primitives such as Column, Row, Button, Text, and Switch." + - id: controlled-switch-state + description: "Must keep Switch value controlled by React state." + - id: host-provides-root + description: "Must render controls under Host." + - id: no-glass-effect + description: "Must not import expo-glass-effect or treat GlassEffect as part of @expo/ui." diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx new file mode 100644 index 00000000..a15a6f02 --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI bottom sheet + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md new file mode 100644 index 00000000..14606951 --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md @@ -0,0 +1 @@ +Replace a gorhom bottom sheet with @expo/ui/community/bottom-sheet and controlled present/dismiss behavior. diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx new file mode 100644 index 00000000..350319b4 --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx @@ -0,0 +1,59 @@ +import { BottomSheet, BottomSheetModalProvider, BottomSheetView } from '@expo/ui/community/bottom-sheet' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const ref = useRef(null) + return ( + + + ref.current?.present()} style={styles.action}>Open sheet + {}}> + Sheet content + + + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml new file mode 100644 index 00000000..62a0b12e --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-bottom-sheet-import + description: "Must import BottomSheet APIs from @expo/ui/community/bottom-sheet." + - id: controlled-present-dismiss + description: "Must expose controlled present/dismiss behavior through a ref or state." + - id: uses-bottom-sheet-view + description: "Must place sheet content in BottomSheetView or documented sheet child wrappers." + - id: no-gorhom-import + description: "Must not import @gorhom/bottom-sheet directly." diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx new file mode 100644 index 00000000..92fed504 --- /dev/null +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI DateTimePicker open API trap + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md new file mode 100644 index 00000000..c289739a --- /dev/null +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md @@ -0,0 +1 @@ +Implement date selection with @expo/ui/community/datetime-picker without using DateTimePickerAndroid.open. diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx new file mode 100644 index 00000000..548a5e56 --- /dev/null +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx @@ -0,0 +1,56 @@ +import { DateTimePicker } from '@expo/ui/community/datetime-picker' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [date, setDate] = useState(new Date()) + return ( + + Date + next && setDate(next)} /> + {date.toDateString()} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml new file mode 100644 index 00000000..3cea615a --- /dev/null +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-datetime-import + description: "Must import DateTimePicker from @expo/ui/community/datetime-picker." + - id: no-android-open-api + description: "Must not use DateTimePickerAndroid.open." + - id: controlled-date-value + description: "Must keep selected Date in controlled state." + - id: handles-undefined-date + description: "Must guard onChange date being undefined when events cancel." diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx new file mode 100644 index 00000000..94a74f6b --- /dev/null +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI DateTimePicker supported props + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md new file mode 100644 index 00000000..1d053306 --- /dev/null +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md @@ -0,0 +1 @@ +Implement cross-platform date/time selection using only supported Expo UI DateTimePicker props and fallback text for unsupported modes. diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx new file mode 100644 index 00000000..6be41e00 --- /dev/null +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx @@ -0,0 +1,56 @@ +import { DateTimePicker } from '@expo/ui/community/datetime-picker' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [date, setDate] = useState(new Date()) + return ( + + Supported picker + setDate(next)} /> + Unsupported native props are intentionally omitted. + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml new file mode 100644 index 00000000..21b8bedc --- /dev/null +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: supported-props-only + description: "Must avoid unsupported community DateTimePicker props from legacy packages." + - id: uses-onchange-or-onvaluechange + description: "Must handle date changes through onChange or onValueChange." + - id: fallback-for-platform-differences + description: "Must render fallback copy for unsupported picker modes/platform behavior." + - id: no-react-native-community-datetimepicker-import + description: "Must not import @react-native-community/datetimepicker directly." diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx new file mode 100644 index 00000000..3d866d9d --- /dev/null +++ b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI Picker drop-in + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md new file mode 100644 index 00000000..867d3cce --- /dev/null +++ b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md @@ -0,0 +1 @@ +Migrate a picker to @expo/ui/community/picker and keep Picker.Item child values controlled. diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx new file mode 100644 index 00000000..e27434cf --- /dev/null +++ b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx @@ -0,0 +1,58 @@ +import { Picker } from '@expo/ui/community/picker' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [value, setValue] = useState('expo') + return ( + + + + + + {value} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml new file mode 100644 index 00000000..8e81eea7 --- /dev/null +++ b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-picker-import + description: "Must import Picker from @expo/ui/community/picker." + - id: picker-item-children + description: "Must declare options with Picker.Item children." + - id: controlled-selected-value + description: "Must keep selectedValue controlled." + - id: no-react-native-picker-import + description: "Must not import @react-native-picker/picker." diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx new file mode 100644 index 00000000..54f49d1a --- /dev/null +++ b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI slider and segmented control + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md new file mode 100644 index 00000000..ff65b46e --- /dev/null +++ b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md @@ -0,0 +1 @@ +Migrate controls to @expo/ui/community slider/segmented-control imports with controlled values. diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx new file mode 100644 index 00000000..4598f7c4 --- /dev/null +++ b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx @@ -0,0 +1,59 @@ +import { Slider } from '@expo/ui/community/slider' +import { SegmentedControl } from '@expo/ui/community/segmented-control' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [value, setValue] = useState(40) + const [segment, setSegment] = useState('daily') + const segments = ['daily', 'weekly'] + return ( + + + + {segment}: {Math.round(value)} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml new file mode 100644 index 00000000..dc6fc420 --- /dev/null +++ b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-slider-import + description: "Must import Slider from @expo/ui/community/slider." + - id: community-segmented-import + description: "Must import SegmentedControl from @expo/ui/community/segmented-control." + - id: controlled-values + description: "Must keep slider and segmented values controlled by state." + - id: no-legacy-community-control-imports + description: "Must not import legacy community slider or segmented-control packages." diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx new file mode 100644 index 00000000..a16a27bf --- /dev/null +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI PagerView + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md new file mode 100644 index 00000000..1e73a6ec --- /dev/null +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md @@ -0,0 +1 @@ +Use @expo/ui/community/pager-view as the drop-in pager and handle page-selected state. diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx new file mode 100644 index 00000000..9ff3d629 --- /dev/null +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx @@ -0,0 +1,58 @@ +import { PagerView } from '@expo/ui/community/pager-view' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [page, setPage] = useState(0) + return ( + + setPage(event.nativeEvent.position)} style={styles.media}> + One + Two + + Page {page + 1} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml new file mode 100644 index 00000000..463923ac --- /dev/null +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-pagerview-import + description: "Must import PagerView from @expo/ui/community/pager-view." + - id: page-selected-state + description: "Must update state from onPageSelected native event position." + - id: stable-page-keys + description: "Must give each page stable keys." + - id: no-react-native-pager-view-import + description: "Must not import react-native-pager-view directly." diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx new file mode 100644 index 00000000..23261fd5 --- /dev/null +++ b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI menu and masked view + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md new file mode 100644 index 00000000..be346f33 --- /dev/null +++ b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md @@ -0,0 +1 @@ +Use @expo/ui/community/menu and @expo/ui/community/masked-view drop-ins with deterministic actions and children. diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx new file mode 100644 index 00000000..7d3ce9f8 --- /dev/null +++ b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx @@ -0,0 +1,59 @@ +import { MaskedView } from '@expo/ui/community/masked-view' +import { MenuView } from '@expo/ui/community/menu' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const [message, setMessage] = useState('No action.') + return ( + + setMessage(nativeEvent.event)}> + Open menu + + Mask}> + {message} + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml new file mode 100644 index 00000000..8381e170 --- /dev/null +++ b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-menu-import + description: "Must import MenuView from @expo/ui/community/menu." + - id: community-masked-view-import + description: "Must import MaskedView from @expo/ui/community/masked-view." + - id: deterministic-menu-actions + description: "Must define deterministic menu action ids/titles and handle selected action." + - id: no-legacy-menu-masked-imports + description: "Must not import legacy menu or masked-view community packages directly." diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx new file mode 100644 index 00000000..d7e68775 --- /dev/null +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI Material colors + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md new file mode 100644 index 00000000..7e19da65 --- /dev/null +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md @@ -0,0 +1 @@ +Use @expo/ui/jetpack-compose Material color helpers inside a Host instead of hardcoding a one-off Android palette. diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx new file mode 100644 index 00000000..1386bfd1 --- /dev/null +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx @@ -0,0 +1,54 @@ +import { Host, Text as MaterialText, useMaterialColors } from '@expo/ui/jetpack-compose' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const colors = useMaterialColors({ seedColor: '#2563eb' }) + return ( + + Material themed text + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml new file mode 100644 index 00000000..d5cc86db --- /dev/null +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: jetpack-compose-entrypoint + description: "Must import Android Material color helpers/components from @expo/ui/jetpack-compose." + - id: uses-material-colors + description: "Must use useMaterialColors or getMaterialColors for palette values." + - id: host-themed-surface + description: "Must render themed UI under the Jetpack Compose Host." + - id: no-hardcoded-only-palette + description: "Must not replace Material colors with only hardcoded hex constants." diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx new file mode 100644 index 00000000..7a78d9db --- /dev/null +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI native state TextInput + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md new file mode 100644 index 00000000..ccc10157 --- /dev/null +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md @@ -0,0 +1 @@ +Use Expo UI TextInput with useNativeState and clean native-state listeners. diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx new file mode 100644 index 00000000..3730c83b --- /dev/null +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -0,0 +1,54 @@ +import { Host, TextInput, useNativeState } from '@expo/ui' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + const value = useNativeState('Expo UI') + return ( + + { value.value = next }} placeholder="Name" /> + + ) +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml new file mode 100644 index 00000000..7f17786a --- /dev/null +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: uses-native-state + description: "Must use useNativeState from @expo/ui for native-shared state." + - id: textinput-controlled + description: "Must wire TextInput value/onChangeText to the native state." + - id: native-state-listener-discipline + description: "Must avoid assigning native state listeners unnecessarily; if a listener is assigned, it must be cleared in cleanup." + - id: host-root + description: "Must render the Expo UI TextInput under Host." diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx new file mode 100644 index 00000000..806a048b --- /dev/null +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx @@ -0,0 +1,44 @@ +import { Pressable, StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Expo UI platform modifiers + Replace this scaffold with the requested Expo implementation. + + Start + + + ) +} + +const styles = StyleSheet.create({ + button: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, +}) diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md new file mode 100644 index 00000000..0d3acc09 --- /dev/null +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md @@ -0,0 +1 @@ +Use SwiftUI/Jetpack modifiers through their platform entrypoints and keep platform-specific code isolated. diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx new file mode 100644 index 00000000..e019a308 --- /dev/null +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx @@ -0,0 +1,55 @@ +import { Platform } from 'react-native' +import { Host as AndroidHost, Text as AndroidText } from '@expo/ui/jetpack-compose' +import { Host as IOSHost, Text as IOSText } from '@expo/ui/swift-ui' +import { background } from '@expo/ui/swift-ui/modifiers' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { AppState, Image, Linking, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' + +export default function App() { + if (Platform.OS === 'ios') { + return iOS native UI + } + return Android native UI +} + +const styles = StyleSheet.create({ + action: { + backgroundColor: '#111827', + borderRadius: 10, + paddingHorizontal: 14, + paddingVertical: 10, + }, + actionText: { + color: '#fff', + fontWeight: '600', + }, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 14, + width: '100%', + }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + overflow: 'hidden', + width: '100%', + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, + }, + subtitle: { + color: '#4b5563', + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '700', + }, +}) diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml new file mode 100644 index 00000000..5455f285 --- /dev/null +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: platform-entrypoints-isolated + description: "Must import SwiftUI APIs from @expo/ui/swift-ui and Jetpack APIs from @expo/ui/jetpack-compose in platform-isolated code." + - id: modifiers-from-platform-package + description: "Must import modifiers from the matching platform modifiers entrypoint." + - id: platform-branch + description: "Must branch platform-specific UI with Platform.OS or platform files." + - id: no-cross-platform-modifier-mixing + description: "Must not pass SwiftUI modifiers to Jetpack components or vice versa." diff --git a/evals/expo-ui/README.md b/evals/expo-ui/README.md new file mode 100644 index 00000000..fcd1e970 --- /dev/null +++ b/evals/expo-ui/README.md @@ -0,0 +1,32 @@ +# Expo UI eval category + +## category overview + +Expo UI evals cover SDK 56 @expo/ui universal components, community drop-in replacements, native state, and platform-specific SwiftUI/Jetpack Compose entrypoints. + +## library baseline and naming + +- Baseline: @expo/ui 56.x. +- Universal components import from @expo/ui. +- Drop-in community replacements import from @expo/ui/community/*. +- SwiftUI and Jetpack Compose APIs import from @expo/ui/swift-ui and @expo/ui/jetpack-compose. +- expo-glass-effect is covered under expo-sdk, not this category. + +## best practices + +### official best-practice sources + +- Expo UI overview: https://docs.expo.dev/versions/latest/sdk/ui/ +- Expo UI universal: https://docs.expo.dev/versions/latest/sdk/ui/universal/ +- Expo UI SwiftUI: https://docs.expo.dev/versions/latest/sdk/ui/swift-ui/ +- Expo UI Jetpack Compose: https://docs.expo.dev/versions/latest/sdk/ui/jetpack-compose/ +- Expo SDK 56 changelog: https://expo.dev/changelog/sdk-56 + +### best-practice inventory + +- U1: Render universal Expo UI native controls under Host. +- U2: Import drop-in replacements from @expo/ui/community/* rather than legacy community packages. +- U3: Keep native component values controlled and handle platform differences explicitly. +- U4: Use useNativeState for native-shared state when required, and clean up listeners. +- U5: Keep platform-specific modifiers and components isolated by platform entrypoint. +- U6: Do not treat expo-glass-effect as part of @expo/ui. diff --git a/package.json b/package.json index da60fe39..9c612b0b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "eslint-config-prettier": "^10.1.5", "eslint-plugin-prettier": "^5.5.1", "eslint-plugin-simple-import-sort": "^12.1.1", - "expo": "^54.0.33", + "expo": "^56", "globals": "^15.14.0", "lefthook": "^2.1.9", "prettier": "^3.8.1" @@ -33,7 +33,7 @@ "@types/bun": "^1.3.8", "ai": "^6.0.78", "ai-sdk-provider-opencode-sdk": "^1.0.0", - "react-native": "^0.84.0", + "react-native": "0.85.3", "typescript": "^5.9.3", "yaml": "^2.8.2", "zod": "^3.23.8" diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 79641baa..1f891f2e 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -70,11 +70,16 @@ \section{React Native methodology} \toprule \textbf{Category} & \textbf{\# Evals} & \textbf{Scope} \\ \midrule -Animation & 14 & React Native animation behavior, including \texttt{Animated} and \texttt{react-native-reanimated}. \\ -Asynchronous state & 14 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ +Animation & 13 & React Native animation behavior, including \texttt{Animated} and \texttt{react-native-reanimated}. \\ +Asynchronous state & 13 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ +Expo Modules & 10 & Static Expo Modules API tasks covering inline modules, native naming, JS wrappers, type generation, config plugins, and scaffolding. \\ +Expo Router & 12 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, data loaders, suspense, and not-found routing. \\ +Expo SDK & 26 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ +Expo UI & 12 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ Lists & 18 & List rendering, item interactions, virtualization patterns, and sectioned data presentation. \\ -Navigation & 15 & Screen transitions, stack/modal flows, route params, and navigation state handling. \\ +Navigation & 13 & Screen transitions, stack/modal flows, route params, and navigation state handling. \\ React Native APIs & 9 & Core platform API usage such as layout, keyboard, accessibility, and device integration primitives. \\ +Skia & 25 & \texttt{@shopify/react-native-skia} drawing, shaders, images, text, gestures, animation, and canvas APIs. \\ \bottomrule \end{tabularx} \caption{Benchmark categories, number of evals per category, and short scope descriptions.} @@ -590,7 +595,7 @@ \section{Conflict of Interest} The authors are affiliated with Callstack. The experiments used commercially available infrastructure acquired and operated independently; no direct sponsorship, funding, or editorial influence was provided for this work. \section{Conclusion} -We evaluated \textbf{18} solver models on the React Native eval suite (\textbf{66} evals in total), with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. +The current repository state contains \textbf{151} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. Two practical implications follow. First, React Native development difficulty is not uniform: models that are competitive on navigation and structural code generation can still be unreliable on behavior-heavy work, where correctness depends on timing, gesture/animation dynamics, and state invalidation semantics. For practitioners, this suggests applying the most scrutiny (and the most automated protection via tests and runtime validation) to animation and async-state code paths, even when a model performs strongly overall. Second, requirement-level evaluation yields actionable signals: per-requirement verdict traces support targeted prompt iteration, scaffolding improvements, and dataset evolution without collapsing all behavior into a single task-level pass/fail. diff --git a/testbench/app.json b/testbench/app.json index 9b8a2c2e..0524bfda 100644 --- a/testbench/app.json +++ b/testbench/app.json @@ -7,5 +7,13 @@ }, "android": { "package": "com.anonymous.evalstestbench" - } + }, + "plugins": [ + "expo-router", + "expo-audio", + "expo-video", + "expo-build-properties", + "expo-status-bar", + "expo-image" + ] } diff --git a/testbench/package.json b/testbench/package.json index 19b4db6c..6c959d56 100644 --- a/testbench/package.json +++ b/testbench/package.json @@ -14,6 +14,7 @@ "harness:ios": "react-native-harness --harnessRunner ios" }, "dependencies": { + "@expo/ui": "~56.0.17", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -23,11 +24,29 @@ "@react-navigation/native-stack": "^7.3.0", "@shopify/flash-list": "^2.3.0", "@tanstack/react-query": "^5.90.21", - "expo": "~54.0.33", - "expo-status-bar": "~3.0.9", + "expo": "^56", + "expo-audio": "~56.0.12", + "expo-build-properties": "~56.0.18", + "expo-calendar": "~56.0.8", + "expo-camera": "~56.0.8", + "expo-constants": "~56.0.18", + "expo-contacts": "~56.0.9", + "expo-file-system": "~56.0.8", + "expo-glass-effect": "~56.0.4", + "expo-image": "~56.0.11", + "expo-image-picker": "~56.0.17", + "expo-location": "~56.0.17", + "expo-media-library": "~56.0.7", + "expo-navigation-bar": "~56.0.3", + "expo-notifications": "~56.0.17", + "expo-router": "~56.2.10", + "expo-status-bar": "~56.0.4", + "expo-task-manager": "~56.0.18", + "expo-updates": "~56.0.19", + "expo-video": "~56.1.3", "jotai": "^2.18.0", - "react": "19.1.0", - "react-native": "0.81.5", + "react": "19.2.3", + "react-native": "0.85.3", "react-native-gesture-handler": "~2.28.0", "react-native-keyboard-controller": "^1.20.7", "react-native-reanimated": "~4.1.1", @@ -37,7 +56,7 @@ }, "devDependencies": { "@react-native-harness/platform-web": "^1.0.0-alpha.25", - "@types/react": "~19.1.0", + "@types/react": "~19.2.0", "react-native-harness": "^1.0.0-alpha.25", "typescript": "~5.9.2" } From 93e9bd29668ac2d42457342ec6851ed4760d0af4 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:19:40 +0400 Subject: [PATCH 02/32] chore(testbench): align Expo SDK 56 packages --- bun.lock | 96 +++++++++++++++++++++++++++--------------- testbench/package.json | 32 +++++++------- 2 files changed, 79 insertions(+), 49 deletions(-) diff --git a/bun.lock b/bun.lock index e06fa463..1c46b114 100644 --- a/bun.lock +++ b/bun.lock @@ -32,7 +32,7 @@ "name": "evals-testbench", "version": "1.0.0", "dependencies": { - "@expo/ui": "~56.0.17", + "@expo/ui": "~56.0.18", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -40,11 +40,11 @@ "@react-navigation/drawer": "^7.3.0", "@react-navigation/native": "^7.1.0", "@react-navigation/native-stack": "^7.3.0", - "@shopify/flash-list": "^2.3.0", + "@shopify/flash-list": "2.0.2", "@tanstack/react-query": "^5.90.21", - "expo": "^56", + "expo": "~56.0.12", "expo-audio": "~56.0.12", - "expo-build-properties": "~56.0.18", + "expo-build-properties": "~56.0.19", "expo-calendar": "~56.0.8", "expo-camera": "~56.0.8", "expo-constants": "~56.0.18", @@ -52,31 +52,31 @@ "expo-file-system": "~56.0.8", "expo-glass-effect": "~56.0.4", "expo-image": "~56.0.11", - "expo-image-picker": "~56.0.17", - "expo-location": "~56.0.17", + "expo-image-picker": "~56.0.18", + "expo-location": "~56.0.18", "expo-media-library": "~56.0.7", "expo-navigation-bar": "~56.0.3", - "expo-notifications": "~56.0.17", - "expo-router": "~56.2.10", + "expo-notifications": "~56.0.18", + "expo-router": "~56.2.11", "expo-status-bar": "~56.0.4", - "expo-task-manager": "~56.0.18", + "expo-task-manager": "~56.0.19", "expo-updates": "~56.0.19", - "expo-video": "~56.1.3", + "expo-video": "~56.1.4", "jotai": "^2.18.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-gesture-handler": "~2.28.0", - "react-native-keyboard-controller": "^1.20.7", - "react-native-reanimated": "~4.1.1", - "react-native-safe-area-context": "~5.6.0", - "react-native-screens": "~4.16.0", + "react-native-gesture-handler": "~2.31.1", + "react-native-keyboard-controller": "1.21.6", + "react-native-reanimated": "4.3.1", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "4.25.2", "zustand": "^5.0.11", }, "devDependencies": { "@react-native-harness/platform-web": "^1.0.0-alpha.25", "@types/react": "~19.2.0", "react-native-harness": "^1.0.0-alpha.25", - "typescript": "~5.9.2", + "typescript": "~6.0.3", }, }, }, @@ -347,7 +347,7 @@ "@expo/sudo-prompt": ["@expo/sudo-prompt@9.3.2", "", {}, "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw=="], - "@expo/ui": ["@expo/ui@56.0.17", "", { "dependencies": { "sf-symbols-typescript": "^2.1.0", "vaul": "^1.1.2" }, "peerDependencies": { "@babel/core": "*", "expo": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-reanimated": "*", "react-native-worklets": "*" }, "optionalPeers": ["@babel/core", "react-dom", "react-native-reanimated", "react-native-worklets"] }, "sha512-Jos9oGzurMDngrSWJesX3LSykPRvkUdANxtq2sPKBc6bAjadtZJCkthAYMaE3P9L5xrzbNRFo+2O76cRP0iYPw=="], + "@expo/ui": ["@expo/ui@56.0.18", "", { "dependencies": { "sf-symbols-typescript": "^2.1.0", "vaul": "^1.1.2" }, "peerDependencies": { "@babel/core": "*", "expo": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-reanimated": "*", "react-native-worklets": "*" }, "optionalPeers": ["@babel/core", "react-dom", "react-native-reanimated", "react-native-worklets"] }, "sha512-2XgH5obigGtXm8zlb/V3g87NSiIcBcJ1xoQOEQYPoExL1DCNsHzaIecTh1XG/f/45ardo4OZNJwpbfYJ9X3qrQ=="], "@expo/ws-tunnel": ["@expo/ws-tunnel@2.0.0", "", { "peerDependencies": { "ws": "^8.0.0" } }, "sha512-j+JfTRdCk820J9dU0sA2SqshQIKFOMo7ED84w9MJFcebfbNQgsLztEY/SABDkGnjatrW4xGqnUhVRxSBVyCkXw=="], @@ -545,7 +545,7 @@ "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], - "@shopify/flash-list": ["@shopify/flash-list@2.3.0", "", { "peerDependencies": { "@babel/runtime": "*", "react": "*", "react-native": "*" } }, "sha512-DR7VuN8KJHTYj9zv1/IhpqrMBMQyeeW/DCWCbVQAAkWhHrc6ylIbXOY+qK93CuHABV+dNHXK/3V6p4wCSW/+wA=="], + "@shopify/flash-list": ["@shopify/flash-list@2.0.2", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@babel/runtime": "*", "react": "*", "react-native": "*" } }, "sha512-zhlrhA9eiuEzja4wxVvotgXHtqd3qsYbXkQ3rsBfOgbFA9BVeErpDE/yEwtlIviRGEqpuFj/oU5owD6ByaNX+w=="], "@sinclair/typebox": ["@sinclair/typebox@0.27.10", "", {}, "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA=="], @@ -605,6 +605,8 @@ "@types/react": ["@types/react@19.2.17", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw=="], + "@types/react-test-renderer": ["@types/react-test-renderer@19.1.0", "", { "dependencies": { "@types/react": "*" } }, "sha512-XD0WZrHqjNrxA/MaR9O22w/RNidWR9YZmBdRGI7wcnWGrv/3dA8wKCJ8m63Sn+tLJhcjmuhOi629N66W6kgWzQ=="], + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], @@ -1013,7 +1015,7 @@ "expo-audio": ["expo-audio@56.0.12", "", { "peerDependencies": { "expo": "*", "expo-asset": "*", "react": "*", "react-native": "*" } }, "sha512-ne2UIO/HsQoBL9e+tGs5N9Sf3NyW5sJMm4sDkexbSJRc2IchLDG+9Msu/+l5N4RlZ8SiF42wRyWsh/Usg+SwOw=="], - "expo-build-properties": ["expo-build-properties@56.0.18", "", { "dependencies": { "@expo/schema-utils": "^56.0.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-at03ytur1Vfyl9ddtRMqIdSyR/oV57GM04+NZ5rhFTF0mC7dmKzxS9RBb34KHDPdT8UwUt7KsKbzYD1lnxLAKg=="], + "expo-build-properties": ["expo-build-properties@56.0.19", "", { "dependencies": { "@expo/schema-utils": "^56.0.0", "resolve-from": "^5.0.0", "semver": "^7.6.0" }, "peerDependencies": { "expo": "*" } }, "sha512-InoviXcxWosNp4cC7L3SWoiY99Xr2HdgN+LYHb6mUm/BBVxy1mIMrZR+3PJ2gwDZzW6EJNDz8ioASWGHBTmzpA=="], "expo-calendar": ["expo-calendar@56.0.8", "", { "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-gxH+J+teP3CBXPybQHuwzTYrFEmSz4irh2n2KSVzzbIRqjVwgVH42op/BViOqxIkMlOlx3hmXNVIkB8RiMtIvg=="], @@ -1035,7 +1037,7 @@ "expo-image-loader": ["expo-image-loader@56.0.3", "", { "peerDependencies": { "expo": "*" } }, "sha512-JgUo4fUeU1ZC+z8iBFj8v7yoGQnZrLbOVPyNE+DWVrld55F2F6R1ck+rmdm/8TNWLz1LhNQfD7c3XYP1ZikxXA=="], - "expo-image-picker": ["expo-image-picker@56.0.17", "", { "dependencies": { "expo-image-loader": "~56.0.3" }, "peerDependencies": { "expo": "*" } }, "sha512-/RojW1ptyQNV89hEeDdaoHCkn38+546MqakMyB0acFf0HLh5ZI7wxQCHkxr16qjuQMy11M+96GlX9Z6vgXF7Nw=="], + "expo-image-picker": ["expo-image-picker@56.0.18", "", { "dependencies": { "expo-image-loader": "~56.0.3" }, "peerDependencies": { "expo": "*" } }, "sha512-sCjQ8M27bhGUv2vUavIE+uWdYo79b2D7Q5h9B66BSDZ+Rd8YyLVSf7vYGfIzQ7nMVoENZ6c4xo/JiDkEeQ9iTg=="], "expo-json-utils": ["expo-json-utils@56.0.0", "", {}, "sha512-lUqyv9aIGDbYTQ5Nux2FnH2/Dz0w5uJ8Pr080eS0StXi2jr5OmuMNErpzUnpfnYOU55xKotd4AHv68PfV/ludg=="], @@ -1043,7 +1045,7 @@ "expo-linking": ["expo-linking@56.0.14", "", { "dependencies": { "expo-constants": "~56.0.18", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-IvVQHWC+Cj4fK5qD3iEVYqpU2a4rLW0IpAAlGJ4MH+H1fyZiHh3eN6qg2WmoclOEPfYATSuEa+dQT6wfgVpXlQ=="], - "expo-location": ["expo-location@56.0.17", "", { "dependencies": { "@expo/image-utils": "^0.10.1" }, "peerDependencies": { "expo": "*" } }, "sha512-3kEONgFApqGzuRhgWyYGb/nXK+rYaeuHtcCYkuVNbrDSlHYYe+mgQPeM4Iuqv43Fihmp0mKsNtq7zX030nE+VA=="], + "expo-location": ["expo-location@56.0.18", "", { "dependencies": { "@expo/image-utils": "^0.10.1" }, "peerDependencies": { "expo": "*" } }, "sha512-6xP0UwGy8a7EEHAMeigYAp3HNo3yWHAg05tVPUfwrOWepWPpFXmjsfUBUxQdkpfpjddJ9r+f4PplxZqKI0LtjA=="], "expo-manifests": ["expo-manifests@56.0.4", "", { "dependencies": { "expo-json-utils": "~56.0.0" }, "peerDependencies": { "expo": "*" } }, "sha512-Fokawl2UkiExIF0bqGoblRFA8lYpROVD+EpvDwSW4LgqQyPwNua1gLSgHZjdl5GsVugfRMMWE3LHaibDyX93hw=="], @@ -1057,9 +1059,9 @@ "expo-navigation-bar": ["expo-navigation-bar@56.0.3", "", { "dependencies": { "debug": "^4.3.2" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-7k8jyJojMs59gIsAPOFk/gCz1BTFy5S0Qf3i2uUW1f2CFoWcQSSyR4VnsmppBkzIKrBzZjcuFmdsZmYO+GZ4og=="], - "expo-notifications": ["expo-notifications@56.0.17", "", { "dependencies": { "@expo/image-utils": "^0.10.1", "abort-controller": "^3.0.0", "badgin": "^1.1.5", "expo-application": "~56.0.3", "expo-constants": "~56.0.18" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-Yn6JUKmoBDkQeznbuUn4cHF2u44r1ErJTneW65MBFt7NLG8U8/VGQ4bBVwswm5nPH1/V92UoXPgvCssScPFRDg=="], + "expo-notifications": ["expo-notifications@56.0.18", "", { "dependencies": { "@expo/image-utils": "^0.10.1", "abort-controller": "^3.0.0", "badgin": "^1.1.5", "expo-application": "~56.0.3", "expo-constants": "~56.0.18" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-HHnrwyCLC5srFojcHYS2KskbNroy9o2fwPKdyhjrdjjrBu4sNRKm4LepcuZjDy98cZKEm89WIPW8O45vut8Rgw=="], - "expo-router": ["expo-router@56.2.10", "", { "dependencies": { "@expo/log-box": "^56.0.13", "@expo/metro-runtime": "^56.0.15", "@expo/schema-utils": "^56.0.0", "@expo/ui": "^56.0.17", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "client-only": "^0.0.1", "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^56.0.4", "expo-server": "^56.0.5", "expo-symbols": "^56.0.6", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", "react-native-screens": "^4.25.2", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^56.0.18", "expo-linking": "^56.0.14", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-u7WcdsFAjSrQS7Bdb1VbNPE3xNcd/BZ6qXSS31UAJKhaYIb+ik3jJSy/W5kY3qKipwbwlo3CSb1WnZ2XYs7F+Q=="], + "expo-router": ["expo-router@56.2.11", "", { "dependencies": { "@expo/log-box": "^56.0.13", "@expo/metro-runtime": "^56.0.15", "@expo/schema-utils": "^56.0.0", "@expo/ui": "^56.0.18", "@radix-ui/react-slot": "^1.2.0", "@radix-ui/react-tabs": "^1.1.12", "@react-native-masked-view/masked-view": "^0.3.2", "@testing-library/jest-dom": "^6.9.1", "@testing-library/user-event": "^14.6.1", "client-only": "^0.0.1", "color": "^4.2.3", "debug": "^4.3.4", "escape-string-regexp": "^4.0.0", "expo-glass-effect": "^56.0.4", "expo-server": "^56.0.5", "expo-symbols": "^56.0.6", "fast-deep-equal": "^3.1.3", "invariant": "^2.2.4", "nanoid": "^3.3.8", "query-string": "^7.1.3", "react-fast-compare": "^3.2.2", "react-is": "^19.1.0", "react-native-drawer-layout": "^4.2.2", "react-native-screens": "^4.25.2", "server-only": "^0.0.1", "sf-symbols-typescript": "^2.1.0", "shallowequal": "^1.1.0", "standard-navigation": "^0.0.5", "vaul": "^1.1.2" }, "peerDependencies": { "@testing-library/react-native": ">= 13.2.0", "expo": "*", "expo-constants": "^56.0.18", "expo-linking": "^56.0.14", "react": "*", "react-dom": "*", "react-native": "*", "react-native-gesture-handler": "*", "react-native-reanimated": "*", "react-native-safe-area-context": ">= 5.4.0", "react-native-web": "*", "react-server-dom-webpack": "~19.0.4 || ~19.1.5 || ~19.2.4" }, "optionalPeers": ["@testing-library/react-native", "react-dom", "react-native-gesture-handler", "react-native-reanimated", "react-native-web", "react-server-dom-webpack"] }, "sha512-08DBTrKv3QanOc9u1JNxSEChW9c/qNFbQ0dO28OLvufWWfdSRkSdHmh365D2FgoZg1qaOzZPCDuL3tM6nGSfkQ=="], "expo-server": ["expo-server@56.0.5", "", {}, "sha512-SmM2p2g3Jrktpiazcst+OxhjSzOHXKAY4BPURHYHXvApzzoybMmrNF4IEZ8DKZ145BhSe4ydAmlEFCRTsdtgUQ=="], @@ -1069,13 +1071,13 @@ "expo-symbols": ["expo-symbols@56.0.6", "", { "dependencies": { "@expo-google-fonts/material-symbols": "^0.4.1", "sf-symbols-typescript": "^2.0.0" }, "peerDependencies": { "expo": "*", "expo-font": "*", "react": "*", "react-native": "*" } }, "sha512-BrA81DjcNafdj7gXVhdrExb9LtUiSVyOf/NavyMmDAHgHMY1GqeR5cnn1PSAZeYKnSgQhee/H89XUpAxtog5hg=="], - "expo-task-manager": ["expo-task-manager@56.0.18", "", { "dependencies": { "unimodules-app-loader": "~56.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-abTKDhlZ572wSwNuZ9HkDw6rl+kKLq0TkqheIEbGoRkMQVEGV3D5GYYY0gg84TO/HvAqiipdcBFQH8+9uHj70Q=="], + "expo-task-manager": ["expo-task-manager@56.0.19", "", { "dependencies": { "unimodules-app-loader": "~56.0.0" }, "peerDependencies": { "expo": "*", "react-native": "*" } }, "sha512-eDeBR8vXlOAXBck29AzPl+tv4QlJus+cgkQ0TGOBqAlgRPWPWd7ebhqrhb0KRieUZIvzlycfcxjHR/+AiEiMHA=="], "expo-updates": ["expo-updates@56.0.19", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/plist": "^0.7.0", "@expo/spawn-async": "^1.8.0", "arg": "^4.1.0", "chalk": "^4.1.2", "debug": "^4.3.4", "expo-eas-client": "~56.0.0", "expo-manifests": "~56.0.4", "expo-structured-headers": "~56.0.0", "expo-updates-interface": "~56.0.1", "getenv": "^2.0.0", "glob": "^13.0.0", "ignore": "^5.3.1", "nullthrows": "^1.1.1", "resolve-from": "^5.0.0" }, "peerDependencies": { "expo": "*", "expo-dev-client": "*", "react": "*", "react-native": "*" }, "optionalPeers": ["expo-dev-client"], "bin": { "expo-updates": "bin/cli.js" } }, "sha512-tTSPYO5h8wDA6a+wQ2v/SRdnOdz29x0npGHCv+4Ev31Fz5r05Ii1Wgfh3BlTXNz8mikMReDsZCf6YN71YeQKpw=="], "expo-updates-interface": ["expo-updates-interface@56.0.2", "", { "peerDependencies": { "expo": "*" } }, "sha512-eWTwSZ9y8vrULG2oBn2TQSSIwBGSq/TxGJ3jY6tuVS2FWH/ASRIiKs3zkUZTRoC3ZuV2alz0mUClYV7nNrFx8g=="], - "expo-video": ["expo-video@56.1.3", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-Ht2BMdx11RnGKxILL/P4t/hl4kqWXq1vLaoOrLZlDed+IXgf8hdDI9jmtEEgsIHwf3jaHFXblJCRVuS9mIxKAw=="], + "expo-video": ["expo-video@56.1.4", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-8mXZOnb7ZsWneDlcnRf0M2Ox9eb5dGnNiGiCkj9bwLPY+3jM2Pc1t5ymNUuhw8lSpT/rOnE0J0/81Y3+0k2Zcw=="], "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], @@ -1685,19 +1687,19 @@ "react-native-drawer-layout": ["react-native-drawer-layout@4.2.2", "", { "dependencies": { "color": "^4.2.3", "use-latest-callback": "^0.2.4" }, "peerDependencies": { "react": ">= 18.2.0", "react-native": "*", "react-native-gesture-handler": ">= 2.0.0", "react-native-reanimated": ">= 2.0.0" } }, "sha512-UG/PTTeyyr43KahbgoGyXri8LMO5USHY3/RUpeKBKwCc7xLVGnDLOVNSRrJw0dDc7YmPbmAyJ4oxp8nKboKKuw=="], - "react-native-gesture-handler": ["react-native-gesture-handler@2.28.0", "", { "dependencies": { "@egjs/hammerjs": "^2.0.17", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-0msfJ1vRxXKVgTgvL+1ZOoYw3/0z1R+Ked0+udoJhyplC2jbVKIJ8Z1bzWdpQRCV3QcQ87Op0zJVE5DhKK2A0A=="], + "react-native-gesture-handler": ["react-native-gesture-handler@2.31.2", "", { "dependencies": { "@egjs/hammerjs": "^2.0.17", "@types/react-test-renderer": "^19.1.0", "hoist-non-react-statics": "^3.3.0", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-rw5q74i2AfS7YGYdbxQDhOU7xqgY6WRM1132/CCm3erqjblhECZDZFHIm0tteHoC9ih24wogVBVVzcTBQtZ+5A=="], "react-native-harness": ["react-native-harness@1.0.0-alpha.25", "", { "dependencies": { "@react-native-harness/babel-preset": "1.0.0-alpha.25", "@react-native-harness/cli": "1.0.0-alpha.25", "@react-native-harness/jest": "1.0.0-alpha.25", "@react-native-harness/metro": "1.0.0-alpha.25", "@react-native-harness/runtime": "1.0.0-alpha.25", "tslib": "^2.3.0" }, "bin": { "react-native-harness": "bin.js", "harness": "bin.js" } }, "sha512-vqkJThgFwxbPBYDWyih/a2ARL0roPl08ga45L968Sd/VnTTOWkfT7pPiKjpLCx0kkyH5Gf196G1yOPhkdh6Yhg=="], "react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.2.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q=="], - "react-native-keyboard-controller": ["react-native-keyboard-controller@1.20.7", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-reanimated": ">=3.0.0" } }, "sha512-G8S5jz1FufPrcL1vPtReATx+jJhT/j+sTqxMIb30b1z7cYEfMlkIzOCyaHgf6IMB2KA9uBmnA5M6ve2A9Ou4kw=="], + "react-native-keyboard-controller": ["react-native-keyboard-controller@1.21.6", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-reanimated": ">=3.0.0" } }, "sha512-nAXCmar/W8Gn4iQV7O5fAVuTh57JszCsqTS+cfR95WFOLR/AfbwfPz/+sWyz/q2SOIe2VpyQzq6hzYiwErhqqw=="], - "react-native-reanimated": ["react-native-reanimated@4.1.6", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1", "semver": "7.7.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0", "react": "*", "react-native": "*", "react-native-worklets": ">=0.5.0" } }, "sha512-F+ZJBYiok/6Jzp1re75F/9aLzkgoQCOh4yxrnwATa8392RvM3kx+fiXXFvwcgE59v48lMwd9q0nzF1oJLXpfxQ=="], + "react-native-reanimated": ["react-native-reanimated@4.3.1", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.3.1", "semver": "^7.7.3" }, "peerDependencies": { "react": "*", "react-native": "0.81 - 0.85", "react-native-worklets": "0.8.x" } }, "sha512-KhGsS0YkCA+gusgyzlf9hnqzVPIR398KTpqXyqq/+yYJJPAvyEEPKcxlB0xtOOXSMrR2A9uRKVARVQhZwrOh+Q=="], - "react-native-safe-area-context": ["react-native-safe-area-context@5.6.2", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-4XGqMNj5qjUTYywJqpdWZ9IG8jgkS3h06sfVjfw5yZQZfWnRFXczi0GnYyFyCc2EBps/qFmoCH8fez//WumdVg=="], + "react-native-safe-area-context": ["react-native-safe-area-context@5.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ=="], - "react-native-screens": ["react-native-screens@4.16.0", "", { "dependencies": { "react-freeze": "^1.0.0", "react-native-is-edge-to-edge": "^1.2.1", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-yIAyh7F/9uWkOzCi1/2FqvNvK6Wb9Y1+Kzn16SuGfN9YFJDTbwlzGRvePCNTOX0recpLQF3kc2FmvMUhyTCH1Q=="], + "react-native-screens": ["react-native-screens@4.25.2", "", { "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": ">=0.82.0" } }, "sha512-1Nj1fusFd+rIMKU/qC9yGKVG+3ofh11d3OdBQKL1iVvQfKvcB8vhvTGQf2TkfxW3bamxN+hCZIXmNuU0mRkyDg=="], "react-native-worklets": ["react-native-worklets@0.7.4", "", { "dependencies": { "@babel/plugin-transform-arrow-functions": "7.27.1", "@babel/plugin-transform-class-properties": "7.27.1", "@babel/plugin-transform-classes": "7.28.4", "@babel/plugin-transform-nullish-coalescing-operator": "7.27.1", "@babel/plugin-transform-optional-chaining": "7.27.1", "@babel/plugin-transform-shorthand-properties": "7.27.1", "@babel/plugin-transform-template-literals": "7.27.1", "@babel/plugin-transform-unicode-regex": "7.27.1", "@babel/preset-typescript": "7.27.1", "convert-source-map": "2.0.0", "semver": "7.7.3" }, "peerDependencies": { "@babel/core": "*", "react": "*", "react-native": "*" } }, "sha512-NYOdM1MwBb3n+AtMqy1tFy3Mn8DliQtd8sbzAVRf9Gc+uvQ0zRfxN7dS8ZzoyX7t6cyQL5THuGhlnX+iFlQTag=="], @@ -2127,14 +2129,16 @@ "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "evals-testbench/expo": ["expo@56.0.12", "", { "dependencies": { "@babel/runtime": "^7.20.0", "@expo/cli": "^56.1.16", "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.9", "@expo/devtools": "~56.0.2", "@expo/dom-webview": "~56.0.5", "@expo/fingerprint": "^0.19.4", "@expo/local-build-cache-provider": "^56.0.8", "@expo/log-box": "^56.0.13", "@expo/metro": "~56.0.0", "@expo/metro-config": "~56.0.14", "@ungap/structured-clone": "^1.3.0", "babel-preset-expo": "~56.0.15", "expo-asset": "~56.0.17", "expo-constants": "~56.0.18", "expo-file-system": "~56.0.8", "expo-font": "~56.0.7", "expo-keep-awake": "~56.0.3", "expo-modules-autolinking": "~56.0.16", "expo-modules-core": "~56.0.17", "pretty-format": "^29.7.0", "react-refresh": "^0.14.2", "whatwg-url-minimum": "^0.1.2" }, "peerDependencies": { "@expo/metro-runtime": "*", "react": "*", "react-dom": "*", "react-native": "*", "react-native-web": "*", "react-native-webview": "*" }, "optionalPeers": ["@expo/metro-runtime", "react-dom", "react-native-web", "react-native-webview"], "bin": { "expo": "bin/cli", "fingerprint": "bin/fingerprint", "expo-modules-autolinking": "bin/autolinking" } }, "sha512-FxgdI/Yqva6iJOThZIHfvxlKPxs4EC4uScUnEswwSArR/Fj9k430O13R590LcOQTsdNsjIs+GBHwjfoAY6vmAQ=="], + + "evals-testbench/typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + "execa/onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], "expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "expo-router/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], - "expo-router/react-native-screens": ["react-native-screens@4.25.2", "", { "dependencies": { "react-freeze": "^1.0.0", "warn-once": "^0.1.0" }, "peerDependencies": { "react": "*", "react-native": ">=0.82.0" } }, "sha512-1Nj1fusFd+rIMKU/qC9yGKVG+3ofh11d3OdBQKL1iVvQfKvcB8vhvTGQf2TkfxW3bamxN+hCZIXmNuU0mRkyDg=="], - "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -2245,7 +2249,7 @@ "react-dom/react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], - "react-native-reanimated/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "react-native-reanimated/react-native-is-edge-to-edge": ["react-native-is-edge-to-edge@1.3.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-NIXU/iT5+ORyCc7p0z2nnlkouYKX425vuU1OEm6bMMtWWR9yvb+Xg5AZmImTKoF9abxCPqrKC3rOZsKzUYgYZA=="], "react-native-worklets/@babel/plugin-transform-class-properties": ["@babel/plugin-transform-class-properties@7.27.1", "", { "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA=="], @@ -2353,6 +2357,16 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.55.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.55.0", "@typescript-eslint/tsconfig-utils": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw=="], + "evals-testbench/expo/@expo/cli": ["@expo/cli@56.1.16", "", { "dependencies": { "@expo/code-signing-certificates": "^0.0.6", "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.9", "@expo/devcert": "^1.2.1", "@expo/env": "~2.3.0", "@expo/image-utils": "^0.10.1", "@expo/inline-modules": "^0.0.12", "@expo/json-file": "^10.2.0", "@expo/log-box": "^56.0.13", "@expo/metro": "~56.0.0", "@expo/metro-config": "~56.0.14", "@expo/metro-file-map": "^56.0.3", "@expo/osascript": "^2.6.0", "@expo/package-manager": "^1.12.1", "@expo/plist": "^0.7.0", "@expo/prebuild-config": "^56.0.16", "@expo/require-utils": "^56.1.3", "@expo/router-server": "^56.0.14", "@expo/schema-utils": "^56.0.0", "@expo/spawn-async": "^1.8.0", "@expo/ws-tunnel": "^2.0.0", "@expo/xcpretty": "^4.4.4", "@react-native/dev-middleware": "0.85.3", "accepts": "^1.3.8", "arg": "^5.0.2", "bplist-creator": "0.1.0", "bplist-parser": "^0.3.1", "chalk": "^4.0.0", "ci-info": "^3.3.0", "compression": "^1.7.4", "connect": "^3.7.0", "debug": "^4.3.4", "dnssd-advertise": "^1.1.4", "expo-server": "^56.0.5", "fetch-nodeshim": "^0.4.10", "getenv": "^2.0.0", "glob": "^13.0.0", "lan-network": "^0.2.1", "multitars": "^1.0.0", "node-forge": "^1.3.3", "npm-package-arg": "^11.0.0", "ora": "^3.4.0", "picomatch": "^4.0.4", "pretty-format": "^29.7.0", "progress": "^2.0.3", "prompts": "^2.3.2", "resolve-from": "^5.0.0", "semver": "^7.6.0", "send": "^0.19.0", "slugify": "^1.3.4", "stacktrace-parser": "^0.1.10", "structured-headers": "^0.4.1", "terminal-link": "^2.1.1", "toqr": "^0.1.1", "wrap-ansi": "^7.0.0", "ws": "^8.12.1", "zod": "^3.25.76" }, "peerDependencies": { "expo": "*", "expo-router": "*", "react-native": "*" }, "optionalPeers": ["expo-router", "react-native"], "bin": { "expo-internal": "main.js" } }, "sha512-VBQn0mqAwc67b9Cn0RVXyeodghomAx5xGRhA/bXaQzuxDjMQk0zIOb6pXMZX7yiIwJW66UZt/zQiJNSv6aWJYw=="], + + "evals-testbench/expo/@expo/config-plugins": ["@expo/config-plugins@56.0.9", "", { "dependencies": { "@expo/config-types": "^56.0.6", "@expo/json-file": "~10.2.0", "@expo/plist": "^0.7.0", "@expo/require-utils": "^56.1.3", "@expo/sdk-runtime-versions": "^1.0.0", "chalk": "^4.1.2", "debug": "^4.3.5", "getenv": "^2.0.0", "glob": "^13.0.0", "semver": "^7.5.4", "slugify": "^1.6.6", "xcode": "^3.0.1", "xml2js": "0.6.0" } }, "sha512-/6a/S9USwx8OC9tGjHxbviLFiBHyueN3aoNWMLvWDEJoZ1CIVW800ZBzwXq/FYNK2qzcN1LxFmQtzD1zeFQKNA=="], + + "evals-testbench/expo/expo-font": ["expo-font@56.0.7", "", { "dependencies": { "fontfaceobserver": "^2.1.0" }, "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-hpU/vRwPzsby9lPGkA4blDqLIIXYzoWnCZHr6PxvcWbY/uPObAiyhh6q+e0WYsB65SthK+PLH95jEnVag7fwEg=="], + + "evals-testbench/expo/expo-modules-autolinking": ["expo-modules-autolinking@56.0.16", "", { "dependencies": { "@expo/require-utils": "^56.1.3", "@expo/spawn-async": "^1.8.0", "chalk": "^4.1.0", "commander": "^7.2.0" }, "bin": { "expo-modules-autolinking": "bin/expo-modules-autolinking.js" } }, "sha512-9JnL4N46P8ubDpDIfWolDn7nxU2j1rY67xY/dNVuyH0m+HG+r/JI16VYtjIf4COpZtEuFo4D3h3MBeFzGucMnw=="], + + "evals-testbench/expo/expo-modules-core": ["expo-modules-core@56.0.17", "", { "dependencies": { "@expo/expo-modules-macros-plugin": "0.2.2", "expo-modules-jsi": "~56.0.10", "invariant": "^2.2.4" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-worklets": "^0.7.4 || ^0.8.0" }, "optionalPeers": ["react-native-worklets"] }, "sha512-5J8whnT7Ccp+BrFClLmpF76omBqn95VZExroTm01Dgjm4vpty1Rb7U3we+ZUceNHtRd07Lw30u7FNfDgIhEbRQ=="], + "execa/onetime/mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], @@ -2483,6 +2497,20 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + "evals-testbench/expo/@expo/cli/@expo/inline-modules": ["@expo/inline-modules@0.0.12", "", { "dependencies": { "@expo/config-plugins": "~56.0.9" } }, "sha512-SNIZr/HWfIQPTZBwmukItxpc7ws1SgMUywYq1dnQvDknQDjJcuWAasIRFUjsK15yQ1xb4G5CP7VHtbN3V4lENg=="], + + "evals-testbench/expo/@expo/cli/@expo/prebuild-config": ["@expo/prebuild-config@56.0.16", "", { "dependencies": { "@expo/config": "~56.0.9", "@expo/config-plugins": "~56.0.9", "@expo/config-types": "^56.0.6", "@expo/image-utils": "^0.10.1", "@expo/json-file": "^10.2.0", "@react-native/normalize-colors": "0.85.3", "debug": "^4.3.1", "expo-modules-autolinking": "~56.0.16", "resolve-from": "^5.0.0", "semver": "^7.6.0" } }, "sha512-ce9ENfPWO4WUWUVQz0OaqL3KYZ7YofP8O35ncnn7CHCaKwQ7BqxcCGJbh+qvP1UjlWeNB3CjHPrXXJ3bnZwlJw=="], + + "evals-testbench/expo/@expo/cli/arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "evals-testbench/expo/@expo/cli/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + + "evals-testbench/expo/@expo/config-plugins/@expo/config-types": ["@expo/config-types@56.0.6", "", {}, "sha512-4Y6Aum5J4Re5NnxGVofRNe1aDwUBOmWhQYkynZsqzRtX/zEA1ADUeyHXuEckv9YD9djiyT7bKtLt5gKL3mA6VQ=="], + + "evals-testbench/expo/expo-modules-autolinking/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "evals-testbench/expo/expo-modules-core/expo-modules-jsi": ["expo-modules-jsi@56.0.10", "", { "peerDependencies": { "react-native": "*" } }, "sha512-fHZcFpYO/o62GYa6fJyAQJZcAShzhoN0iMMDzbr7vD3ewET6e1vAlTonbEakN9F0VHEgBFJ4NREy87uwVcpCuA=="], + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "jest-circus/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], @@ -2541,6 +2569,8 @@ "eslint-plugin-expo/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + "evals-testbench/expo/@expo/cli/@expo/prebuild-config/@expo/config-types": ["@expo/config-types@56.0.6", "", {}, "sha512-4Y6Aum5J4Re5NnxGVofRNe1aDwUBOmWhQYkynZsqzRtX/zEA1ADUeyHXuEckv9YD9djiyT7bKtLt5gKL3mA6VQ=="], + "jest-cli/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "jest-environment-node/jest-validate/pretty-format/@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], diff --git a/testbench/package.json b/testbench/package.json index 6c959d56..426008ba 100644 --- a/testbench/package.json +++ b/testbench/package.json @@ -14,7 +14,7 @@ "harness:ios": "react-native-harness --harnessRunner ios" }, "dependencies": { - "@expo/ui": "~56.0.17", + "@expo/ui": "~56.0.18", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -22,11 +22,11 @@ "@react-navigation/drawer": "^7.3.0", "@react-navigation/native": "^7.1.0", "@react-navigation/native-stack": "^7.3.0", - "@shopify/flash-list": "^2.3.0", + "@shopify/flash-list": "2.0.2", "@tanstack/react-query": "^5.90.21", - "expo": "^56", + "expo": "~56.0.12", "expo-audio": "~56.0.12", - "expo-build-properties": "~56.0.18", + "expo-build-properties": "~56.0.19", "expo-calendar": "~56.0.8", "expo-camera": "~56.0.8", "expo-constants": "~56.0.18", @@ -34,30 +34,30 @@ "expo-file-system": "~56.0.8", "expo-glass-effect": "~56.0.4", "expo-image": "~56.0.11", - "expo-image-picker": "~56.0.17", - "expo-location": "~56.0.17", + "expo-image-picker": "~56.0.18", + "expo-location": "~56.0.18", "expo-media-library": "~56.0.7", "expo-navigation-bar": "~56.0.3", - "expo-notifications": "~56.0.17", - "expo-router": "~56.2.10", + "expo-notifications": "~56.0.18", + "expo-router": "~56.2.11", "expo-status-bar": "~56.0.4", - "expo-task-manager": "~56.0.18", + "expo-task-manager": "~56.0.19", "expo-updates": "~56.0.19", - "expo-video": "~56.1.3", + "expo-video": "~56.1.4", "jotai": "^2.18.0", "react": "19.2.3", "react-native": "0.85.3", - "react-native-gesture-handler": "~2.28.0", - "react-native-keyboard-controller": "^1.20.7", - "react-native-reanimated": "~4.1.1", - "react-native-safe-area-context": "~5.6.0", - "react-native-screens": "~4.16.0", + "react-native-gesture-handler": "~2.31.1", + "react-native-keyboard-controller": "1.21.6", + "react-native-reanimated": "4.3.1", + "react-native-safe-area-context": "~5.7.0", + "react-native-screens": "4.25.2", "zustand": "^5.0.11" }, "devDependencies": { "@react-native-harness/platform-web": "^1.0.0-alpha.25", "@types/react": "~19.2.0", "react-native-harness": "^1.0.0-alpha.25", - "typescript": "~5.9.2" + "typescript": "~6.0.3" } } From 2d904f49b2e6861cb513a15549c221e90b96c517 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:20:10 +0400 Subject: [PATCH 03/32] fix(expo-router): configure data loader eval --- .../09-rn-expo-router-data-loaders-config/app/app.json | 8 ++++++++ .../reference/app.json | 8 +++++++- .../requirements.yaml | 3 ++- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json new file mode 100644 index 00000000..d5f9f747 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json @@ -0,0 +1,8 @@ +{ + "expo": { + "plugins": ["expo-router"], + "web": { + "bundler": "metro" + } + } +} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json index ceca201d..cd134733 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json @@ -1,7 +1,13 @@ { "expo": { "plugins": [ - ["expo-router", { "asyncRoutes": true }] + [ + "expo-router", + { + "unstable_useServerDataLoaders": true, + "unstable_useServerRendering": true + } + ] ], "web": { "bundler": "metro", diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml index a3019503..46116e76 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml @@ -1,6 +1,7 @@ version: 1 inputs: files: + - app/app.json - app/_layout.tsx - app/index.tsx requirements: @@ -9,6 +10,6 @@ requirements: - id: uses-use-loader-data description: "Must read loader results with useLoaderData typed to the loader." - id: router-plugin-configured - description: "Must configure expo-router/app config for data-loader compatible web/server output." + description: "Must configure the expo-router plugin with unstable_useServerDataLoaders and web output set to static or server." - id: no-client-fetch-duplication description: "Must not duplicate the same data fetch in a client mount effect." From f8b46e9daded2b5d87ec0ccd9f9043cba96076d4 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:20:40 +0400 Subject: [PATCH 04/32] fix(expo-modules): make inline module note judgeable --- .../01-rn-expo-modules-inline-config/app/INLINE_MODULES.md | 3 +++ .../01-rn-expo-modules-inline-config/app/app.json | 5 +++++ .../app/src/modules/DeviceAuditModule.kt | 3 +++ .../reference/INLINE_MODULES.md | 3 +++ .../01-rn-expo-modules-inline-config/requirements.yaml | 3 +++ 5 files changed, 17 insertions(+) create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt create mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md new file mode 100644 index 00000000..66ce1cf2 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md @@ -0,0 +1,3 @@ +# Inline Modules + +Add any build or prebuild notes for inline module config changes here. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json b/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json new file mode 100644 index 00000000..ade285c8 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json @@ -0,0 +1,5 @@ +{ + "expo": { + "experiments": {} + } +} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt new file mode 100644 index 00000000..8578ba71 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt @@ -0,0 +1,3 @@ +package expo.modules.deviceaudit + +// Replace with an Expo ModuleDefinition inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md new file mode 100644 index 00000000..1d318895 --- /dev/null +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md @@ -0,0 +1,3 @@ +# Inline Modules + +Changing `expo.experiments.inlineModules` or its `watchedDirectories` requires regenerating the native project with `npx expo prebuild` or rebuilding the development client so the generated module providers include the inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml index 4bdefe3b..226feb13 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml @@ -2,6 +2,9 @@ version: 1 inputs: files: - app/App.tsx + - app/INLINE_MODULES.md + - app/app.json + - app/src/modules/DeviceAuditModule.kt requirements: - id: inline-modules-enabled description: "Must set expo.experiments.inlineModules in app config." From f80e113c99472318333a3b4c5caffea12d942896 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:21:36 +0400 Subject: [PATCH 05/32] fix(expo-modules): correct web platform eval --- .../app/expo-module.config.json | 5 +++++ .../app/src/AuditModule.ts | 7 +++++++ .../app/src/index.ts | 7 +++++++ .../reference/expo-module.config.json | 7 +++---- .../reference/src/AuditModule.ts | 7 +++++++ .../reference/src/AuditModule.web.ts | 6 +++++- .../reference/src/index.ts | 8 ++++---- .../requirements.yaml | 11 +++++++---- 8 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json new file mode 100644 index 00000000..bb030e50 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json @@ -0,0 +1,5 @@ +{ + "platforms": ["apple", "android"], + "apple": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] } +} diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts new file mode 100644 index 00000000..1dc8e5c7 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts @@ -0,0 +1,7 @@ +import { requireNativeModule } from 'expo-modules-core' + +export type AuditModule = { + getPlatform(): string +} + +export default requireNativeModule('AuditModule') diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts new file mode 100644 index 00000000..837598e4 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts @@ -0,0 +1,7 @@ +import AuditModule from './AuditModule' + +export function getPlatform() { + return AuditModule.getPlatform() +} + +export default AuditModule diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json index 497ef4df..a037d2f3 100644 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json @@ -1,6 +1,5 @@ { - "platforms": ["ios", "android", "web"], - "ios": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] }, - "web": { "modules": ["src/AuditModule.web.ts"] } + "platforms": ["apple", "android", "web"], + "apple": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] } } diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts new file mode 100644 index 00000000..1dc8e5c7 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts @@ -0,0 +1,7 @@ +import { requireNativeModule } from 'expo-modules-core' + +export type AuditModule = { + getPlatform(): string +} + +export default requireNativeModule('AuditModule') diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts index f3ab2d43..a1a9ba3a 100644 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts @@ -1,5 +1,9 @@ -export default { +import type { AuditModule } from './AuditModule' + +const AuditModuleWeb: AuditModule = { getPlatform() { return 'web' }, } + +export default AuditModuleWeb diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts index 7721ee50..837598e4 100644 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts @@ -1,7 +1,7 @@ -import { requireNativeModule } from 'expo-modules-core' +import AuditModule from './AuditModule' -type AuditModule = { - getPlatform(): string +export function getPlatform() { + return AuditModule.getPlatform() } -export default requireNativeModule('AuditModule') +export default AuditModule diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml b/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml index b313f88c..3bcc9204 100644 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml @@ -2,12 +2,15 @@ version: 1 inputs: files: - app/App.tsx + - app/expo-module.config.json + - app/src/AuditModule.ts + - app/src/index.ts requirements: - id: platform-added-to-config - description: "Must add the new platform to expo-module.config.json." + description: "Must add web to expo-module.config.json platforms without adding an unsupported web.modules block." - id: platform-implementation-file - description: "Must include an implementation file for the added platform." + description: "Must include a .web.ts implementation file for the added platform." - id: js-export-preserved - description: "Must preserve the JS/TS public export surface." + description: "Must preserve the JS/TS public export surface and route exports through a platform-resolved module file." - id: autolinking-not-broken - description: "Must not remove existing iOS/Android autolinking module declarations while adding the new platform." + description: "Must not remove existing Apple/iOS or Android native module declarations while adding web." From 2e376b9b97e01d3be84b078346746bd98e0584d5 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:22:19 +0400 Subject: [PATCH 06/32] fix(expo-sdk): tighten media library asset reference --- .../reference/App.tsx | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx index 27fb0201..9e13ad7e 100644 --- a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx @@ -1,7 +1,14 @@ import { File, Paths } from 'expo-file-system' import * as MediaLibrary from 'expo-media-library' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +const transparentPng = Uint8Array.from([ + 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, + 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 13, 73, 68, 65, + 84, 120, 156, 99, 248, 255, 255, 63, 0, 5, 254, 2, 254, 167, 53, 129, 132, + 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, +]) export default function App() { const [message, setMessage] = useState('No asset saved.') @@ -12,11 +19,19 @@ export default function App() { setMessage('Cannot save without photo permission.') return } - const file = new File(Paths.cache, 'generated-photo.txt') - file.write('placeholder-image-bytes') + const file = new File(Paths.cache, 'generated-photo.png') + file.write(transparentPng) + if (!file.exists) { + setMessage('Generated file was not written.') + return + } const asset = await MediaLibrary.Asset.create(file.uri) - const album = (await MediaLibrary.Album.get('Exports')) ?? await MediaLibrary.Album.create('Exports', [asset], false) - await album.add(asset) + const album = await MediaLibrary.Album.get('Exports') + if (album) { + await album.add(asset) + } else { + await MediaLibrary.Album.create('Exports', [asset], false) + } setMessage(await asset.getFilename()) } @@ -40,21 +55,6 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, screen: { backgroundColor: '#fff', flex: 1, From d403dc07cdc823033dcb99c3c4a394027ddb4c34 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:23:22 +0400 Subject: [PATCH 07/32] chore(expo-modules): seed static eval inputs --- .../app/app.json | 9 +++++++++ .../app/src/modules/DirectoryAuditModule.kt | 3 +++ .../requirements.yaml | 2 ++ .../03-rn-expo-modules-swift-name-match/app/index.ts | 1 + .../app/modules/WeatherInlineModule.swift | 3 +++ .../requirements.yaml | 2 ++ .../04-rn-expo-modules-kotlin-name-match/app/index.ts | 1 + .../app/modules/WeatherInlineModule.kt | 3 +++ .../requirements.yaml | 2 ++ .../app/src/NativeDeviceAudit.ts | 1 + .../app/src/index.ts | 1 + .../requirements.yaml | 2 ++ .../app/ios/AuditLabelModule.swift | 3 +++ .../app/ios/AuditLabelView.swift | 3 +++ .../app/src/AuditLabel.tsx | 1 + .../requirements.yaml | 3 +++ .../app/build/index.d.ts | 1 + .../app/expo-module.config.json | 5 +++++ .../app/src/index.ts | 1 + .../requirements.yaml | 3 +++ .../app/app.config.ts | 5 +++++ .../app/plugin/withAuditPermissions.ts | 1 + .../requirements.yaml | 2 ++ .../app/README.md | 3 +++ .../app/scripts/create-module.sh | 4 ++++ .../requirements.yaml | 2 ++ 26 files changed, 67 insertions(+) create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json create mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts create mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md create mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json new file mode 100644 index 00000000..7051eb71 --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json @@ -0,0 +1,9 @@ +{ + "expo": { + "experiments": { + "inlineModules": { + "watchedDirectories": [] + } + } + } +} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt new file mode 100644 index 00000000..61f46aca --- /dev/null +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt @@ -0,0 +1,3 @@ +package expo.modules.directoryaudit + +// Add the inline module inside a valid watched project subdirectory. diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml index a001d3c1..7c1a1773 100644 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml +++ b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/app.json + - app/src/modules/DirectoryAuditModule.kt requirements: - id: watched-directories-valid description: "Must configure watchedDirectories as project subdirectories, not ./, /, ../, or parent directories." diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts new file mode 100644 index 00000000..47a4aea8 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts @@ -0,0 +1 @@ +// Export the inline Swift module wrapper from here. diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift new file mode 100644 index 00000000..c30d2df0 --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift @@ -0,0 +1,3 @@ +import ExpoModulesCore + +// Replace with a Swift inline module whose file, class, and Name match. diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml index b5a33850..38326bf1 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/index.ts + - app/modules/WeatherInlineModule.swift requirements: - id: swift-file-class-match description: "Must make the Swift file name match the Swift module class name." diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts new file mode 100644 index 00000000..f70fcc2a --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts @@ -0,0 +1 @@ +// Export the inline Kotlin module wrapper from here. diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt new file mode 100644 index 00000000..763c209d --- /dev/null +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt @@ -0,0 +1,3 @@ +package expo.modules.weatherinline + +// Replace with a Kotlin inline module whose file, class, and Name match. diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml index 17be49b6..cdced043 100644 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/index.ts + - app/modules/WeatherInlineModule.kt requirements: - id: kotlin-file-class-match description: "Must make the Kotlin file name match the Kotlin module class name." diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts new file mode 100644 index 00000000..532936e2 --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts @@ -0,0 +1 @@ +// Wrap the native module with requireNativeModule and export typed helpers. diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts new file mode 100644 index 00000000..cb46f69e --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts @@ -0,0 +1 @@ +// Re-export the public JS helper from here. diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml index ba312aff..9cb47540 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/src/NativeDeviceAudit.ts + - app/src/index.ts requirements: - id: uses-require-native-module description: "Must import requireNativeModule from expo-modules-core." diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift new file mode 100644 index 00000000..155a9093 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift @@ -0,0 +1,3 @@ +import ExpoModulesCore + +// Define the native module and its View(...) declaration here. diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift new file mode 100644 index 00000000..8ed87882 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift @@ -0,0 +1,3 @@ +import ExpoModulesCore + +// Define the ExpoView subclass used by the module. diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx new file mode 100644 index 00000000..beaa7ac0 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx @@ -0,0 +1 @@ +// Wrap the native view manager and expose typed props/events. diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml index de8dafa1..22c182c6 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml @@ -2,6 +2,9 @@ version: 1 inputs: files: - app/App.tsx + - app/ios/AuditLabelModule.swift + - app/ios/AuditLabelView.swift + - app/src/AuditLabel.tsx requirements: - id: view-definition-used description: "Must define a View(...) in the native module definition." diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts new file mode 100644 index 00000000..9033df27 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts @@ -0,0 +1 @@ +// Commit generated public TypeScript declarations here. diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json new file mode 100644 index 00000000..bb030e50 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json @@ -0,0 +1,5 @@ +{ + "platforms": ["apple", "android"], + "apple": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] } +} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts new file mode 100644 index 00000000..83716f6c --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts @@ -0,0 +1 @@ +// Export public runtime helpers and public TypeScript types from here. diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml index 85c0c136..6523b180 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml @@ -2,6 +2,9 @@ version: 1 inputs: files: - app/App.tsx + - app/build/index.d.ts + - app/expo-module.config.json + - app/src/index.ts requirements: - id: expo-module-config-platforms description: "Must keep expo-module.config.json platforms and module class names explicit." diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts new file mode 100644 index 00000000..607d4885 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts @@ -0,0 +1,5 @@ +export default { + expo: { + plugins: [], + }, +} diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts new file mode 100644 index 00000000..a94a94f6 --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts @@ -0,0 +1 @@ +// Export a ConfigPlugin that writes iOS and Android permission config. diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml index b5027555..3bb8e6c9 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/app.config.ts + - app/plugin/withAuditPermissions.ts requirements: - id: config-plugin-export description: "Must export a ConfigPlugin from the plugin file." diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md new file mode 100644 index 00000000..3ff5d04a --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md @@ -0,0 +1,3 @@ +# expo-audit-module scaffold + +Document the deterministic noninteractive module scaffold here. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh new file mode 100644 index 00000000..b4f2fcd8 --- /dev/null +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Replace with a noninteractive create-expo-module command. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml index 2324e340..54cd3db9 100644 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml @@ -2,6 +2,8 @@ version: 1 inputs: files: - app/App.tsx + - app/README.md + - app/scripts/create-module.sh requirements: - id: noninteractive-command description: "Must provide a noninteractive create-expo-module command or script." From 8d981f93cbb04059d517e15067b7c5b85a7b29bc Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:23:53 +0400 Subject: [PATCH 08/32] docs(expo-sdk): add missing official sources --- evals/expo-sdk/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evals/expo-sdk/README.md b/evals/expo-sdk/README.md index 133f087d..00c9694c 100644 --- a/evals/expo-sdk/README.md +++ b/evals/expo-sdk/README.md @@ -25,12 +25,14 @@ Expo SDK evals cover current SDK 56 behavior across Expo capability modules, per - Expo FileSystem: https://docs.expo.dev/versions/latest/sdk/filesystem/ - Expo MediaLibrary: https://docs.expo.dev/versions/latest/sdk/media-library/ - Expo Calendar: https://docs.expo.dev/versions/latest/sdk/calendar/ +- Expo Contacts: https://docs.expo.dev/versions/latest/sdk/contacts/ - Expo Audio: https://docs.expo.dev/versions/latest/sdk/audio/ - Expo Video: https://docs.expo.dev/versions/latest/sdk/video/ - Expo Updates: https://docs.expo.dev/versions/latest/sdk/updates/ - Expo StatusBar: https://docs.expo.dev/versions/latest/sdk/status-bar/ - Expo NavigationBar: https://docs.expo.dev/versions/latest/sdk/navigation-bar/ - Expo BuildProperties: https://docs.expo.dev/versions/latest/sdk/build-properties/ +- Expo GlassEffect: https://docs.expo.dev/versions/latest/sdk/glass-effect/ ### best-practice inventory From 5dff70f7d79490dee53727ac3760439153ba94a5 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Thu, 25 Jun 2026 02:23:59 +0400 Subject: [PATCH 09/32] docs(whitepaper): clarify eval metadata contract --- paper/benchmark-methodology-whitepaper.tex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 1f891f2e..5fd81087 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -61,7 +61,7 @@ \section{React Native methodology} The meritorious content of this benchmark is concentrated around validation of primitive Large Language Models without any external augmentations such as RAG, documentation access or agent skills. The purpose of this benchmark is to assess how those models perform in the task of React Native development including the most common third party libraries in the React Native ecosystem. -The benchmark we propose in this work includes evaluation cases (referred to as \textit{evals}), divided into categories; each eval consists of multiple requirements as to the outputs of the evaluated model (referred to as \textit{solver}), as described in \cref{sec:generation,sec:judgement}. Finally, the solver performs the task in each evaluation, and in the second stage of the benchmark, another LLM (referred to as \textit{judge}) assesses the result by assigning scores to each of the requirements, along with generating a justification in natural language (for interpretability). The breakdown of the categories of evals is presented in \cref{tab:category-evals-scope}. For the sake of this experiment, the chosen requirements were adjusted such that they mattered equally, thus implying weights of all requirements being set to $1.0$. +The benchmark we propose in this work includes evaluation cases (referred to as \textit{evals}), divided into categories; each eval consists of multiple requirements as to the outputs of the evaluated model (referred to as \textit{solver}), as described in \cref{sec:generation,sec:judgement}. Finally, the solver performs the task in each evaluation, and in the second stage of the benchmark, another LLM (referred to as \textit{judge}) assesses the result by assigning scores to each of the requirements, along with generating a justification in natural language (for interpretability). The breakdown of the categories of evals is presented in \cref{tab:category-evals-scope}. Requirements default to a weight of $1.0$ when no explicit weight is provided, while individual evals may set positive custom weights where finer scoring granularity is useful. \begin{table}[htbp] \centering @@ -238,7 +238,7 @@ \subsubsection{\texttt{prompt.md}} \subsubsection{\texttt{app/}} -The \texttt{app/} directory must contain all files serving as baseline input provided to the solver. The files that shall be evaluated by the judge must be listed in the \texttt{requirements.yaml} file. +The \texttt{app/} directory contains the baseline input files provided to the solver. The current generation runner copies the full \texttt{app/} directory for each eval; by authoring convention, files that are expected as baseline inputs should also be listed in the \texttt{requirements.yaml} metadata so eval scope remains auditable. \subsection{Judgement stage inputs} \label{sec:judgement} @@ -289,7 +289,7 @@ \subsubsection{\texttt{requirements.yaml}} Task prompt used by the solver model. A representative logical template of this type of file is presented in \cref{lst:requirements-yaml-template}. The \mintinline{yaml}{version} is a constant element present for compatibility reasons for future versions of the project, that must be set to \mintinline{yaml}{1}. -The \mintinline{yaml}{inputs} list shall contain all files to be copied to the temporary workspace for the solver. +The \mintinline{yaml}{inputs} list documents the intended baseline files for the eval. In the current runner it is metadata rather than the copy source of truth: generation copies the full eval \texttt{app/} directory to the temporary solver workspace. The \mintinline{yaml}{requirements} list shall contain all the requirements, described in natural language. The requirements should explicitly state specific elements or behaviors that the presence of is to be asserted in the judgement stage. Optionally, each requirement may contain a \mintinline{yaml}{weight} value set to a positive value to emphasize its impact on the score for that requirement. If omitted, its value defaults to \mintinline{yaml}{1}. From 99d3d85f16a8df74b905e30782517d1cb8c650ad Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 00:01:32 +0400 Subject: [PATCH 10/32] fix(evals): audit fixes across expo-sdk, expo-router, expo-modules, expo-ui Address blocking, should-fix, and nice-to-have issues found during fresh-context eval audit: replace unshipped Stack.Toolbar API with headerRight options, fix platform key consistency, remove dead links and orphan files, add missing input stubs, tighten requirement language for judgeability, and clean up unused code in references. Co-Authored-By: Claude Opus 4.6 --- .../requirements.yaml | 2 -- .../requirements.yaml | 4 ++-- .../requirements.yaml | 4 ++-- .../prompt.md | 2 +- .../reference/expo-module.config.json | 7 +++---- .../reference/index.tsx | 2 -- .../reference/details.tsx | 7 ------- .../requirements.yaml | 2 -- .../reference/_layout.tsx | 17 +++++++++++------ .../requirements.yaml | 8 ++++---- .../reference/_layout.tsx | 4 +--- .../requirements.yaml | 2 +- .../app/profile.tsx | 5 +++++ .../app/server/profile.server.ts | 3 +++ .../requirements.yaml | 2 ++ .../app/index.tsx | 4 ---- .../app/+not-found.tsx | 5 +++++ .../app/[...slug].tsx | 5 +++++ .../requirements.yaml | 2 ++ .../requirements.yaml | 2 +- .../reference/App.tsx | 15 ++------------- .../requirements.yaml | 2 +- .../requirements.yaml | 2 +- 23 files changed, 52 insertions(+), 56 deletions(-) delete mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml index 226feb13..2acb15aa 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml @@ -12,5 +12,3 @@ requirements: description: "Must place inline native files in a configured watched directory." - id: module-dsl-used description: "Must define the native module with Expo Module/ModuleDefinition DSL." - - id: prebuild-note - description: "Must make it clear that changing inlineModules config requires prebuild/build regeneration." diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml index 38326bf1..f1675319 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml @@ -8,8 +8,8 @@ requirements: - id: swift-file-class-match description: "Must make the Swift file name match the Swift module class name." - id: swift-name-matches-class - description: "Must set Name(\"...\") to the same module name or omit it only when inference is correct." + description: "Must set Name(\"...\") to match the class name, or omit Name when the class name already matches." - id: uses-expo-modules-core description: "Must import ExpoModulesCore and conform to Module." - - id: js-wrapper-same-name + - id: swift-js-wrapper-same-name description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml index cdced043..62475a07 100644 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml @@ -8,8 +8,8 @@ requirements: - id: kotlin-file-class-match description: "Must make the Kotlin file name match the Kotlin module class name." - id: kotlin-name-matches-class - description: "Must set Name(\"...\") to the same module name or omit it only when inference is correct." + description: "Must set Name(\"...\") to match the class name, or omit Name when the class name already matches." - id: uses-kotlin-module-dsl description: "Must extend expo.modules.kotlin.modules.Module and return ModuleDefinition." - - id: js-wrapper-same-name + - id: kotlin-js-wrapper-same-name description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md index 52e91b0f..49bb2926 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md @@ -1 +1 @@ -Define an Expo module View with typed props, events, and a JS wrapper that forwards props safely. +Define an Expo module View with typed props, events, and a JS wrapper that forwards props safely. (iOS) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json index 09915d51..bb030e50 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json @@ -1,6 +1,5 @@ { - "platforms": ["ios", "android"], - "ios": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] }, - "apple": { "modules": ["AuditModule"] } + "platforms": ["apple", "android"], + "apple": { "modules": ["AuditModule"] }, + "android": { "modules": ["expo.modules.audit.AuditModule"] } } diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx index 307c5221..66f93c34 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/index.tsx @@ -1,11 +1,9 @@ -import { Link } from 'expo-router' import { Text, View } from 'react-native' export default function Index() { return ( Home - Details ) } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx deleted file mode 100644 index 97fa5eb9..00000000 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { useLocalSearchParams } from 'expo-router' -import { Text, View } from 'react-native' - -export default function Details() { - const { id } = useLocalSearchParams<{ id?: string }>() - return Product {id ?? 'unknown'} -} diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml index 31290969..eed21c81 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml @@ -10,5 +10,3 @@ requirements: description: "Must not call createNativeStackNavigator or NavigationContainer in Expo Router app code." - id: registers-screens-by-name description: "Must configure Stack.Screen entries by file-route names." - - id: route-file-present - description: "Must include a route file matching each configured screen." diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx index 0e379e8e..70fa084f 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx @@ -1,14 +1,19 @@ import { Stack } from 'expo-router' -import { Alert } from 'react-native' +import { Alert, Pressable, Text } from 'react-native' export default function Layout() { return ( - - - Alert.alert('New item')} /> - - + ( + Alert.alert('New item')}> + + + + ), + }} + /> ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml index e4dbbeb5..f62eb04e 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml @@ -4,11 +4,11 @@ inputs: - app/_layout.tsx - app/index.tsx requirements: - - id: uses-stack-toolbar-components - description: "Must compose header actions with Stack.Toolbar child components." + - id: uses-stack-screen-options-for-header + description: "Must compose header actions via Stack.Screen options (headerRight/headerLeft), not Stack.Toolbar." - id: route-options-in-layout description: "Must keep screen options in Expo Router Stack layout/screen configuration." - id: action-callback-defined description: "Must wire header action callbacks to deterministic handlers." - - id: no-react-navigation-headerleft - description: "Must not import React Navigation header types/components directly." + - id: no-react-navigation-header-imports + description: "Must not import React Navigation header components or types directly." diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx index 1ef12db8..253148fd 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/_layout.tsx @@ -4,12 +4,10 @@ export default function Layout() { return ( - Home - + Home Settings - ) diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml index 46116e76..74ba153c 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml @@ -10,6 +10,6 @@ requirements: - id: uses-use-loader-data description: "Must read loader results with useLoaderData typed to the loader." - id: router-plugin-configured - description: "Must configure the expo-router plugin with unstable_useServerDataLoaders and web output set to static or server." + description: "Must configure the expo-router plugin with unstable_useServerDataLoaders, unstable_useServerRendering, and web output set to server." - id: no-client-fetch-duplication description: "Must not duplicate the same data fetch in a client mount effect." diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx new file mode 100644 index 00000000..c06a0dfd --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function Profile() { + return Profile +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts new file mode 100644 index 00000000..7861e23c --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts @@ -0,0 +1,3 @@ +export async function getProfile() { + return {} +} diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml index 003357c4..d0626103 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml @@ -3,6 +3,8 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/profile.tsx + - app/server/profile.server.ts requirements: - id: server-only-code-isolated description: "Must place server-only secret/env access in a server-only module or loader boundary." diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx index dee6ae56..66f93c34 100644 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx @@ -1,9 +1,5 @@ import { Text, View } from 'react-native' -export function SuspenseFallback() { - return Loading... -} - export default function Index() { return ( diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx new file mode 100644 index 00000000..12a76b95 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function NotFound() { + return Not Found +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx new file mode 100644 index 00000000..464e5359 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx @@ -0,0 +1,5 @@ +import { Text } from 'react-native' + +export default function CatchAll() { + return Catch All +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml b/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml index c0b57674..7507ce54 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml @@ -3,6 +3,8 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/+not-found.tsx + - app/[...slug].tsx requirements: - id: plus-not-found-route description: "Must implement +not-found.tsx as the not-found route." diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml index c86a4caa..4507ece8 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/requirements.yaml @@ -12,6 +12,6 @@ requirements: - id: single-flight-permission-request description: "Must prevent overlapping permission prompts with a request-in-flight state or equivalent guard." - id: expo-camera-grant-gated-preview - description: "Must render CameraView only when the current permission object is granted and show deterministic fallback UI otherwise." + description: "Must gate CameraView rendering behind a granted permission check and show deterministic fallback UI for all other permission states." - id: implementation-expo-camera-current-api description: "Must use CameraView and useCameraPermissions or current get/request camera permission APIs from expo-camera." diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx index d5b21b57..3b434103 100644 --- a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx +++ b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx @@ -1,6 +1,6 @@ import { useVideoPlayer, VideoView } from 'expo-video' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect } from 'react' +import { AppState, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { const player = useVideoPlayer('https://example.com/demo.mp4', (nextPlayer) => { @@ -38,14 +38,6 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, media: { backgroundColor: '#e5e7eb', borderRadius: 12, @@ -59,9 +51,6 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { - color: '#4b5563', - }, title: { color: '#111827', fontSize: 20, diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml b/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml index fa78ff2d..06f9aeda 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml @@ -8,6 +8,6 @@ requirements: - id: host-root-wraps-native-ui description: "Must render Expo UI native components inside a Host root." - id: rn-host-view-only-for-rn-children - description: "Must use RNHostView only when intentionally hosting React Native children inside native UI." + description: "Must not use RNHostView unless embedding React Native children inside a native UI subtree." - id: no-glass-effect description: "Must not import expo-glass-effect or treat GlassEffect as part of @expo/ui." diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml index 7f17786a..e74d8fee 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml @@ -8,6 +8,6 @@ requirements: - id: textinput-controlled description: "Must wire TextInput value/onChangeText to the native state." - id: native-state-listener-discipline - description: "Must avoid assigning native state listeners unnecessarily; if a listener is assigned, it must be cleared in cleanup." + description: "Must clear native state listeners in cleanup." - id: host-root description: "Must render the Expo UI TextInput under Host." From 868c7cbf9d3c13571a3956de4edf99e279f2283c Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 00:19:02 +0400 Subject: [PATCH 11/32] fix(evals): rewrite prompts to be scenario-focused, not prescriptive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrite all Expo eval prompts so they describe WHAT to build or fix, not HOW to do it. Requirements test whether the model knows the right APIs and patterns — prompts should not give away the answer. Also merges expo-modules eval 02 (watchedDirectories rules) into eval 01 (inline-config) since the standalone eval had no natural prompt that didn't prescribe the solution. Co-Authored-By: Claude Opus 4.6 --- .../prompt.md | 2 +- .../requirements.yaml | 4 ++ .../app/App.tsx | 44 ------------------- .../app/app.json | 9 ---- .../app/src/modules/DirectoryAuditModule.kt | 3 -- .../prompt.md | 1 - .../reference/app.json | 9 ---- .../src/modules/DirectoryAuditModule.kt | 10 ----- .../requirements.yaml | 15 ------- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../21-rn-expo-video-player-view/prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../08-rn-expo-ui-pagerview-drop-in/prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- 66 files changed, 62 insertions(+), 149 deletions(-) delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt delete mode 100644 evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md b/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md index 357c8510..c3c91779 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md @@ -1 +1 @@ -Enable Expo inline modules in app config and add a minimal Kotlin or Swift inline module inside a watched project directory. +The project has a native Kotlin module at src/modules/DeviceAuditModule.kt that should work as an Expo inline module. Make whatever changes are needed so the module is recognized by the Expo build system. \ No newline at end of file diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml index 2acb15aa..3003d1f6 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml @@ -10,5 +10,9 @@ requirements: description: "Must set expo.experiments.inlineModules in app config." - id: watched-directory-valid description: "Must place inline native files in a configured watched directory." + - id: no-overlapping-watched-dirs + description: "Must not include both a directory and its nested child in watchedDirectories." + - id: no-special-router-group-path + description: "Must not put special-character route groups such as app/(tabs) in watchedDirectories." - id: module-dsl-used description: "Must define the native module with Expo Module/ModuleDefinition DSL." diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx deleted file mode 100644 index 719400b3..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo Modules 2 - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json deleted file mode 100644 index 7051eb71..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "expo": { - "experiments": { - "inlineModules": { - "watchedDirectories": [] - } - } - } -} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt deleted file mode 100644 index 61f46aca..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/app/src/modules/DirectoryAuditModule.kt +++ /dev/null @@ -1,3 +0,0 @@ -package expo.modules.directoryaudit - -// Add the inline module inside a valid watched project subdirectory. diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md deleted file mode 100644 index 95b95361..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Configure inline module watchedDirectories with valid project subdirectories and avoid invalid root, parent, duplicate, or special-character paths. diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json deleted file mode 100644 index 0c066de0..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "expo": { - "experiments": { - "inlineModules": { - "watchedDirectories": ["app", "src/modules"] - } - } - } -} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt deleted file mode 100644 index 87269e4d..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/reference/src/modules/DirectoryAuditModule.kt +++ /dev/null @@ -1,10 +0,0 @@ -package expo.modules.directoryaudit - -import expo.modules.kotlin.modules.Module -import expo.modules.kotlin.modules.ModuleDefinition - -class DirectoryAuditModule : Module() { - override fun definition() = ModuleDefinition { - Name("DirectoryAuditModule") - } -} diff --git a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml b/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml deleted file mode 100644 index 7c1a1773..00000000 --- a/evals/expo-modules/02-rn-expo-modules-inline-watched-directories-rules/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/app.json - - app/src/modules/DirectoryAuditModule.kt -requirements: - - id: watched-directories-valid - description: "Must configure watchedDirectories as project subdirectories, not ./, /, ../, or parent directories." - - id: no-overlapping-watched-dirs - description: "Must not include both a directory and its nested child in watchedDirectories." - - id: no-special-router-group-path - description: "Must not put special-character route groups such as app/(tabs) in watchedDirectories." - - id: nested-files-covered-by-parent - description: "Must rely on the parent watched directory to include nested inline module files." diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md b/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md index 52401d58..ec2bea1e 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md @@ -1 +1 @@ -Create a Swift inline module whose file name, class name, and module Name all match. +The existing Swift inline module at modules/WeatherInlineModule.swift is not being picked up at runtime. Fix it so the module loads correctly and is accessible from JS. \ No newline at end of file diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md index 1677a055..d021ed14 100644 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md +++ b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md @@ -1 +1 @@ -Create a Kotlin inline module whose file name, class name, and module Name all match. +The existing Kotlin inline module at modules/WeatherInlineModule.kt is not being picked up at runtime. Fix it so the module loads correctly and is accessible from JS. \ No newline at end of file diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md index f3bd8fca..f9ac6beb 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md @@ -1 +1 @@ -Wrap a native module with requireNativeModule from expo-modules-core and expose typed JS helpers. +Create a typed JS wrapper module for the DeviceAudit native module so consumers have type-safe access to its functions. \ No newline at end of file diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md index 49bb2926..e6af7ae6 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md @@ -1 +1 @@ -Define an Expo module View with typed props, events, and a JS wrapper that forwards props safely. (iOS) +Build a native iOS label component (AuditLabel) exposed as a React component. It should display text and notify JS when the user interacts with it. \ No newline at end of file diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md index e63a67d9..468ddb1d 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md @@ -1 +1 @@ -Configure Expo modules type generation with stable output paths and committed generated TypeScript surfaces. +The package exports TypeScript types but consumers report the types are missing after install. Ensure the generated TypeScript declarations are available and exported correctly from the package. \ No newline at end of file diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md index c03236cf..7e3e36ca 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md @@ -1 +1 @@ -Create a config plugin that adds platform permission strings idempotently through Expo config-plugins. +The app needs camera access on both iOS and Android. Create a local config plugin that ensures the necessary permissions are declared in the native projects during prebuild. \ No newline at end of file diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md index 9ab48af6..e58ef64b 100644 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md +++ b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md @@ -1 +1 @@ -Document/script a noninteractive create-expo-module scaffold with deterministic package name and platforms. +Create a shell script that scaffolds a new Expo module for the project's CI pipeline. The script must work in a headless environment with no human interaction. \ No newline at end of file diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md index 6b0890d0..ff39ea24 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/prompt.md @@ -1 +1 @@ -Migrate an Expo Router layout to SDK 56 import boundaries: use expo-router exports in app code and avoid direct @react-navigation imports. +Migrate an Expo Router layout to SDK 56 import conventions. \ No newline at end of file diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md index 3aaa068f..9b2099aa 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md @@ -1 +1 @@ -Implement a stack layout using Expo Router Stack, not createNativeStackNavigator, and keep route files file-system based. +Implement a stack layout in an Expo Router app with a main and details screen. \ No newline at end of file diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md index a7214509..87719a81 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md @@ -1 +1 @@ -Compose Expo Router Stack header buttons/search/title with Stack child components and route-level options. +Add a back button and title to a screen header in an Expo Router app. \ No newline at end of file diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md index b2426cfd..d799063a 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md @@ -1 +1 @@ -Implement an iOS large-title screen whose scroll content is the first child and whose options live in Expo Router Stack. +Build an iOS screen with a large collapsing title that collapses on scroll. \ No newline at end of file diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md index 0a99b8ba..96b93fe0 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md @@ -1 +1 @@ -Build native tabs with expo-router/unstable-native-tabs and explicit Trigger entries for every tab. +Build a bottom tab layout using Expo Router's native tabs API. \ No newline at end of file diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md index da015cc8..2c9ec4f2 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md @@ -1 +1 @@ -Configure native tabs with selected/default labels, icons, and badges using NativeTabs.Trigger child APIs. +Configure native tab icons, labels, and badges with selected and default states. \ No newline at end of file diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md index 4d8050a2..b61cbe4e 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md @@ -1 +1 @@ -Protect authenticated Expo Router routes with Stack.Protected or Tabs.Protected and a deterministic signed-out fallback. +Implement authentication-gated routes in an Expo Router app with a signed-out fallback. \ No newline at end of file diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md index 9ca4fc50..483a5a23 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md @@ -1 +1 @@ -Implement navigation with serializable search params and decode them safely with Expo Router hooks. +Navigate between routes in an Expo Router app and read params on the destination screen. \ No newline at end of file diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md b/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md index 426ef90e..42a5e755 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md @@ -1 +1 @@ -Enable Expo Router data loaders for web and use loader/useLoaderData in a route. +Enable pre-render data fetching for a route in an Expo Router web app. \ No newline at end of file diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md index 21bfe7f5..8d8db8ee 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md @@ -1 +1 @@ -Split static loader-safe data from server-only code and avoid importing server secrets into client routes. +Fetch data in an Expo Router web route while keeping server secrets out of the client bundle. \ No newline at end of file diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md index b71796ac..c2514a3a 100644 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md @@ -1 +1 @@ -Use Expo Router's route-level SuspenseFallback export for async route content. +Add a loading fallback for async route content in an Expo Router layout. \ No newline at end of file diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md b/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md index 70e9f4cc..236c696f 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md @@ -1 +1 @@ -Implement a +not-found route that has priority over catch-all content and gives users a route back home. +Handle unknown routes gracefully and give users a way back to known content. \ No newline at end of file diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md index 404e6abe..8206eff4 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md @@ -1 +1 @@ -Build a production-ready camera entry flow with expo-camera. Request camera access only when the user initiates it, handle retry and settings-recovery states, keep permission state accurate after returning from settings, and render CameraView only while access is granted. +Build a production-ready camera entry flow with expo-camera that handles all permission states, including denial and the user returning from system settings. \ No newline at end of file diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md index 74ea2bd3..eff17bda 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md @@ -1 +1 @@ -Implement a camera preview that pauses native camera work when the screen is backgrounded, manually disabled, or no longer focused, and fully unmounts CameraView when access is not available. +Build a camera preview screen that handles being backgrounded, switching away, or manually disabled. The camera should work correctly when the user returns to the screen. \ No newline at end of file diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md index 546fc5c9..38cd7bb9 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md @@ -1 +1 @@ -Build a combined barcode scanner and video-ready camera screen with expo-camera. Configure barcode types explicitly, avoid stale BarCodeScanner APIs, and request microphone permission only when the user enables video capture with audio. +Build a camera screen that scans barcodes and optionally records video with audio. Handle permissions appropriately and use current expo-camera APIs. \ No newline at end of file diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md index 5cb5e7d5..d65046c9 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md @@ -1 +1 @@ -Implement an image picker flow that handles cancellation safely, reads the current SDK result shape, and renders a deterministic empty state when no asset was selected. +Implement an image picker flow that lets the user select an image from their library and displays it. Handle all outcomes of the picker gracefully. \ No newline at end of file diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md index 406c1587..2e17a2ac 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md @@ -1 +1 @@ -Build a video-library picker that models media-library permission separately from picking, handles limited/denied access, and uses the current mediaTypes value shape. +Build a video-library picker that lets the user select a video from their library. Handle all permission states and picker outcomes correctly. \ No newline at end of file diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md index 34960b50..c2934bb5 100644 --- a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md @@ -1 +1 @@ -Implement a foreground location flow that requests permission on demand, guards geocoding behind granted foreground access, and handles empty reverse-geocode results without crashing. +Implement a foreground location flow that requests permission on demand, retrieves the user's current location, and reverse-geocodes it to a human-readable address. \ No newline at end of file diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md index 0b792fe7..e1603a3d 100644 --- a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md @@ -1 +1 @@ -Create a background-location opt-in screen. It must ask for foreground permission before background permission, register a TaskManager task once, and avoid starting updates until both permissions are granted. +Create a screen that lets the user opt into background location tracking. Use expo-location and TaskManager to receive location updates when the app is in the background. \ No newline at end of file diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md index c3e1c457..99dd9a1c 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md @@ -1 +1 @@ -Build a foreground-location status panel that distinguishes permission status from accuracy/authorization details and degrades gracefully when exact accuracy is unavailable. +Build a foreground-location status panel that shows the user's current location permission state and accuracy level. Handle all the ways permission and accuracy can differ across platforms. \ No newline at end of file diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md index b9b96f6e..a3901222 100644 --- a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md @@ -1 +1 @@ -Implement push-notification registration that creates an Android channel before requesting an Expo push token, handles permission denial, and passes an EAS projectId when requesting the token. +Implement push-notification registration using expo-notifications. The app should obtain an Expo push token and be ready to receive notifications on both platforms. \ No newline at end of file diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md index 7ab6777c..11d9d445 100644 --- a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md @@ -1 +1 @@ -Create a notification inbox component that subscribes to foreground notifications and response taps, updates local state, and cleans up every subscription on unmount. +Create a notification inbox component that displays notifications received while the app is in the foreground and tracks when the user taps a notification. \ No newline at end of file diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md index e430e9d8..a8b38f57 100644 --- a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md +++ b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md @@ -1 +1 @@ -Build a push-token helper that resolves projectId from Expo Constants, handles missing projectId in Expo Go or local builds, and never calls getExpoPushTokenAsync with an undefined projectId. +Build a push-token registration helper that works correctly in both development and production environments. It should gracefully handle cases where token registration is not possible. \ No newline at end of file diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md index 5cf61341..f6f9187a 100644 --- a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md @@ -1 +1 @@ -Move notification native configuration into the expo-notifications config plugin. Do not use the removed top-level notification field in app config. +Configure native notification settings (icon, color, default channel) for an Expo project using current SDK conventions. The project has notification configuration in app.config.ts that may need updating. \ No newline at end of file diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md index 8050727b..e4f8cee8 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md @@ -1 +1 @@ -Implement a cache-backed notes file using the current expo-file-system object API. Create directories idempotently, write text, read text, and avoid root-level legacy functions that throw in SDK 56. +Implement a simple notes feature that persists text to a cache file using expo-file-system. The app should handle first-run (no existing file) gracefully. \ No newline at end of file diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md index 54881d44..6fe5243f 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md @@ -1 +1 @@ -Repair a file helper that still uses legacy FileSystem method names. Either migrate it to the object API or import legacy methods from expo-file-system/legacy; do not use runtime-throwing root exports. +A file helper is broken after an SDK upgrade — file operations crash at runtime. Fix it so the helper works with the current version of expo-file-system. \ No newline at end of file diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md index de3d0056..679d97f6 100644 --- a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md @@ -1 +1 @@ -Implement a download-and-upload flow with the current expo-file-system File API. Download into a cache Directory/File destination, expose progress/status, and upload the File as a Blob-compatible value with fetch/FormData. +Implement a flow that downloads a remote file to local storage and then uploads it to a server endpoint. Use expo-file-system and show download progress. \ No newline at end of file diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md index b8e1c03d..b17c17ea 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md @@ -1 +1 @@ -Create a save-to-photos permission flow that requests write-only photo access with Android granular permissions and clearly separates write-only from read-library access. +Create a feature that saves a generated image to the user's photo library. The app only needs to save photos, not browse existing ones. Handle permissions appropriately on both platforms. \ No newline at end of file diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md index 49722e6c..f40458dd 100644 --- a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md @@ -1 +1 @@ -Implement a generated-image save flow using expo-media-library current class APIs. Create an Asset from a file path and optionally add it to an Album without using stale root createAssetAsync. +Implement a feature that saves a locally generated image to the user's media library and organizes it into an album. Use current expo-media-library APIs. \ No newline at end of file diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md index e9b09d60..bb8c053a 100644 --- a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md @@ -1 +1 @@ -Build a calendar-event creation screen that uses the current expo-calendar API surface, handles permission denial, and avoids legacy Async helpers that now live behind legacy warnings. +Build a screen that lets the user create a calendar event. Use expo-calendar to list available calendars, pick one, and create the event. Handle permission denial gracefully. \ No newline at end of file diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md index e474a6ab..54fcf409 100644 --- a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md @@ -1 +1 @@ -Implement a contacts lookup screen that requests contacts permission on demand, queries only the fields it renders, and handles empty contact lists and denied permission. +Build a contacts lookup screen that displays the user's contacts with names, emails, and photos. Handle permission denial and empty contact lists. \ No newline at end of file diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md index c4289bad..f1e319b5 100644 --- a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md @@ -1 +1 @@ -Build an audio preview component with expo-audio, not expo-av. Use the managed player hook, subscribe to player status, configure audio mode deliberately, and release/stop playback on lifecycle changes. +Build an audio preview component that plays a sound file, shows playback status, and handles app lifecycle correctly (backgrounding, unmount). Use current Expo audio APIs. \ No newline at end of file diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md b/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md index 458af2eb..5fdfc88f 100644 --- a/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md +++ b/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md @@ -1 +1 @@ -Build a video player using expo-video. Create the player with useVideoPlayer, render it with VideoView, avoid expo-av Video, and clean up or pause playback when the component loses visibility. +Build a video player component that plays a video URL, supports looping and mute controls, and handles visibility changes properly. Use current Expo video APIs. \ No newline at end of file diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md index c5f6afa9..8a47e2bc 100644 --- a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md @@ -1 +1 @@ -Replace a stale expo-video-thumbnails helper with expo-video thumbnail generation. Generate thumbnails from the VideoPlayer, handle empty output, and avoid importing expo-video-thumbnails. +A video thumbnail feature is broken after an SDK upgrade. Fix it to generate thumbnail images from a video file at specific time offsets using current Expo APIs. Handle cases where no thumbnails are generated. \ No newline at end of file diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md index 22e4ade4..6d7d5c3c 100644 --- a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md @@ -1 +1 @@ -Create an update-ready screen with expo-updates. Use useUpdates for state/progress, show a reload screen while applying a downloaded update, and avoid unsafe JS assumptions after reloadAsync resolves. +Create a screen that checks for OTA updates, shows download progress, and applies the update when ready. Use expo-updates and handle errors and the case where no update is available. \ No newline at end of file diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md b/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md index b8b5f83f..8e5c8197 100644 --- a/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md @@ -1 +1 @@ -Implement a release-channel switcher that updates expo-updates request headers at runtime, clears overrides when returning to default, and avoids persisting stale cohort headers across sessions. +Implement a UI that lets users switch between release channels (e.g., production, staging, beta) and check for updates from the selected channel. Use expo-updates. \ No newline at end of file diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md index 75fc49e8..f8375809 100644 --- a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md @@ -1 +1 @@ -Build a screen-level system UI controller using current expo-status-bar, expo-navigation-bar, and expo-glass-effect APIs. Prefer component/namespace APIs, gate Liquid Glass usage with availability checks, and clean up listeners. +Build a screen that controls the system status bar and navigation bar appearance and optionally applies a glass/blur effect when the platform supports it. Clean up properly on unmount. \ No newline at end of file diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md index af7729e5..ad100e3c 100644 --- a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md @@ -1 +1 @@ -Configure expo-build-properties for an SDK 56 project that opts into iOS precompiled React Native dependencies and Android build properties without using stale property names. +Configure build properties for an SDK 56 Expo project. The iOS build should use prebuilt dependencies where possible, and Android SDK versions should match current requirements. Use the expo-build-properties config plugin. \ No newline at end of file diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md index 6cac575e..6ede98f8 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md @@ -1 +1 @@ -Build a universal Expo UI screen with Host as the native UI root and React Native content only where it is intentionally hosted. +Build a universal Expo UI screen that renders native UI components alongside React Native content. \ No newline at end of file diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md index 5bf5cabd..80a9d41c 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md @@ -1 +1 @@ -Build a settings panel with Expo UI universal Column/Row/Text/Button/Switch controls and controlled state. +Build a settings panel in App.tsx using Expo UI universal layout and control components with controlled state. \ No newline at end of file diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md index 14606951..b5a537f8 100644 --- a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md @@ -1 +1 @@ -Replace a gorhom bottom sheet with @expo/ui/community/bottom-sheet and controlled present/dismiss behavior. +Migrate the bottom sheet in App.tsx to use the Expo UI equivalent with controlled open and close behavior. \ No newline at end of file diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md index c289739a..314f19ea 100644 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md @@ -1 +1 @@ -Implement date selection with @expo/ui/community/datetime-picker without using DateTimePickerAndroid.open. +Add cross-platform date selection to the app using Expo UI's date/time picker. \ No newline at end of file diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md index 1d053306..66e71b4c 100644 --- a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md @@ -1 +1 @@ -Implement cross-platform date/time selection using only supported Expo UI DateTimePicker props and fallback text for unsupported modes. +Add cross-platform date and time selection to App.tsx using Expo UI, handling any platform differences gracefully. \ No newline at end of file diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md index 867d3cce..c175915a 100644 --- a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md +++ b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md @@ -1 +1 @@ -Migrate a picker to @expo/ui/community/picker and keep Picker.Item child values controlled. +Migrate the picker in App.tsx to the Expo UI equivalent with controlled selection. \ No newline at end of file diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md index ff65b46e..1d465cc1 100644 --- a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md +++ b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md @@ -1 +1 @@ -Migrate controls to @expo/ui/community slider/segmented-control imports with controlled values. +Migrate the slider and segmented control in App.tsx to their Expo UI equivalents. \ No newline at end of file diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md index 1e73a6ec..750e370c 100644 --- a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md @@ -1 +1 @@ -Use @expo/ui/community/pager-view as the drop-in pager and handle page-selected state. +Replace the pager implementation in App.tsx with the Expo UI pager and track the active page. \ No newline at end of file diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md index be346f33..d5492814 100644 --- a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md +++ b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md @@ -1 +1 @@ -Use @expo/ui/community/menu and @expo/ui/community/masked-view drop-ins with deterministic actions and children. +Migrate the context menu and masked view in App.tsx to their Expo UI equivalents. \ No newline at end of file diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md index 7e19da65..37356b40 100644 --- a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md @@ -1 +1 @@ -Use @expo/ui/jetpack-compose Material color helpers inside a Host instead of hardcoding a one-off Android palette. +The Android screen in App.tsx uses hardcoded color values. Refactor it to use the platform's dynamic color system through Expo UI. \ No newline at end of file diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md index ccc10157..84455481 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md @@ -1 +1 @@ -Use Expo UI TextInput with useNativeState and clean native-state listeners. +Build a text input in App.tsx using Expo UI that shares its value with the native layer and properly cleans up subscriptions. \ No newline at end of file diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md index 0d3acc09..85667563 100644 --- a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md @@ -1 +1 @@ -Use SwiftUI/Jetpack modifiers through their platform entrypoints and keep platform-specific code isolated. +Add platform-specific native styling modifiers to the Expo UI components in App.tsx, supporting both iOS and Android. \ No newline at end of file From d026b17124cba20d8fb34debd5cc22475ef8cd29 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 00:24:45 +0400 Subject: [PATCH 12/32] chore(evals): remove redundant and low-signal Expo evals Drop six evals that test trivial knowledge or duplicate existing coverage: - expo-modules/09 (create-module-noninteractive): tests CLI-flag memorization, not engineering - expo-modules/04 (kotlin-name-match): duplicates the Swift name-match eval; same concept in a second language - expo-ui/06, 07, 09 (picker, slider/segmented, menu/masked-view drop-ins): pure import swaps with 1:1 API parity, redundant with the bottom-sheet drop-in - expo-sdk/11 (notifications project-id guard): substantively a subset of the android-channel-token eval Co-Authored-By: Claude Opus 4.6 --- .../app/App.tsx | 44 ----------- .../app/index.ts | 1 - .../app/modules/WeatherInlineModule.kt | 3 - .../prompt.md | 1 - .../reference/index.ts | 3 - .../reference/modules/WeatherInlineModule.kt | 13 ---- .../requirements.yaml | 15 ---- .../app/App.tsx | 44 ----------- .../app/README.md | 3 - .../app/scripts/create-module.sh | 4 - .../prompt.md | 1 - .../reference/README.md | 3 - .../reference/scripts/create-module.sh | 4 - .../requirements.yaml | 15 ---- .../app/App.tsx | 44 ----------- .../prompt.md | 1 - .../reference/App.tsx | 73 ------------------- .../requirements.yaml | 15 ---- .../app/App.tsx | 44 ----------- .../prompt.md | 1 - .../reference/App.tsx | 58 --------------- .../requirements.yaml | 13 ---- .../app/App.tsx | 44 ----------- .../prompt.md | 1 - .../reference/App.tsx | 59 --------------- .../requirements.yaml | 13 ---- .../app/App.tsx | 44 ----------- .../prompt.md | 1 - .../reference/App.tsx | 59 --------------- .../requirements.yaml | 13 ---- 30 files changed, 637 deletions(-) delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt delete mode 100644 evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh delete mode 100644 evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml delete mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx delete mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md delete mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx delete mode 100644 evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml delete mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx delete mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md delete mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx delete mode 100644 evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml delete mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx delete mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md delete mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx delete mode 100644 evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml delete mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx delete mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md delete mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx delete mode 100644 evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx deleted file mode 100644 index 52d3bbb3..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo Modules 4 - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts deleted file mode 100644 index f70fcc2a..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/index.ts +++ /dev/null @@ -1 +0,0 @@ -// Export the inline Kotlin module wrapper from here. diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt deleted file mode 100644 index 763c209d..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/app/modules/WeatherInlineModule.kt +++ /dev/null @@ -1,3 +0,0 @@ -package expo.modules.weatherinline - -// Replace with a Kotlin inline module whose file, class, and Name match. diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md deleted file mode 100644 index d021ed14..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/prompt.md +++ /dev/null @@ -1 +0,0 @@ -The existing Kotlin inline module at modules/WeatherInlineModule.kt is not being picked up at runtime. Fix it so the module loads correctly and is accessible from JS. \ No newline at end of file diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts deleted file mode 100644 index 942fed50..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt deleted file mode 100644 index bebb1758..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/reference/modules/WeatherInlineModule.kt +++ /dev/null @@ -1,13 +0,0 @@ -package expo.modules.weatherinline - -import expo.modules.kotlin.modules.Module -import expo.modules.kotlin.modules.ModuleDefinition - -class WeatherInlineModule : Module() { - override fun definition() = ModuleDefinition { - Name("WeatherInlineModule") - Function("unit") { - "celsius" - } - } -} diff --git a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml b/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml deleted file mode 100644 index 62475a07..00000000 --- a/evals/expo-modules/04-rn-expo-modules-kotlin-name-match/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/index.ts - - app/modules/WeatherInlineModule.kt -requirements: - - id: kotlin-file-class-match - description: "Must make the Kotlin file name match the Kotlin module class name." - - id: kotlin-name-matches-class - description: "Must set Name(\"...\") to match the class name, or omit Name when the class name already matches." - - id: uses-kotlin-module-dsl - description: "Must extend expo.modules.kotlin.modules.Module and return ModuleDefinition." - - id: kotlin-js-wrapper-same-name - description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx deleted file mode 100644 index 63e3a7bb..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo Modules 9 - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md deleted file mode 100644 index 3ff5d04a..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# expo-audit-module scaffold - -Document the deterministic noninteractive module scaffold here. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh deleted file mode 100644 index b4f2fcd8..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/app/scripts/create-module.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Replace with a noninteractive create-expo-module command. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md deleted file mode 100644 index e58ef64b..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Create a shell script that scaffolds a new Expo module for the project's CI pipeline. The script must work in a headless environment with no human interaction. \ No newline at end of file diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md deleted file mode 100644 index 82341920..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# expo-audit-module scaffold - -Run the script from the repository root to create the module noninteractively with fixed name and platforms. diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh deleted file mode 100644 index 18799f2b..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/reference/scripts/create-module.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -npx create-expo-module@latest expo-audit-module --platforms ios,android --package-name expo-audit-module --no-install diff --git a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml b/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml deleted file mode 100644 index 54cd3db9..00000000 --- a/evals/expo-modules/09-rn-expo-modules-create-module-noninteractive/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/README.md - - app/scripts/create-module.sh -requirements: - - id: noninteractive-command - description: "Must provide a noninteractive create-expo-module command or script." - - id: fixed-package-name - description: "Must set a deterministic module/package name." - - id: fixed-platforms - description: "Must specify target platforms explicitly." - - id: no-interactive-prompts - description: "Must avoid instructions that require answering interactive prompts during evaluation." diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx deleted file mode 100644 index bc88cdff..00000000 --- a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Notifications project id guard - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md deleted file mode 100644 index a8b38f57..00000000 --- a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Build a push-token registration helper that works correctly in both development and production environments. It should gracefully handle cases where token registration is not possible. \ No newline at end of file diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx deleted file mode 100644 index 8e7d17c8..00000000 --- a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/reference/App.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import Constants from 'expo-constants' -import * as Notifications from 'expo-notifications' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' - -export default function App() { - const [message, setMessage] = useState('Ready.') - - const getToken = async () => { - const projectId = Constants.easConfig?.projectId ?? Constants.expoConfig?.extra?.eas?.projectId - if (!projectId) { - setMessage('Push tokens require an EAS project id; configure extra.eas.projectId for this build.') - return - } - const permission = await Notifications.requestPermissionsAsync() - if (!permission.granted) { - setMessage('Notification permission denied.') - return - } - const token = await Notifications.getExpoPushTokenAsync({ projectId }) - setMessage(token.data) - } - - return ( - - Project token - {message} - Get token - - ) -} - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml b/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml deleted file mode 100644 index 45409b32..00000000 --- a/evals/expo-sdk/11-rn-expo-notifications-project-id-expo-go-guard/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: project-id-from-constants - description: "Must derive projectId from Constants.easConfig?.projectId or Constants.expoConfig?.extra?.eas?.projectId." - - id: undefined-project-id-guard - description: "Must branch before getExpoPushTokenAsync when projectId is missing." - - id: expo-go-or-dev-message - description: "Must render a clear local-development/Expo Go fallback message for missing projectId." - - id: permission-before-token - description: "Must request notification permission before requesting the push token." - - id: token-request-passes-object - description: "Must call getExpoPushTokenAsync with an options object containing projectId." diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx deleted file mode 100644 index 3d866d9d..00000000 --- a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo UI Picker drop-in - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md deleted file mode 100644 index c175915a..00000000 --- a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Migrate the picker in App.tsx to the Expo UI equivalent with controlled selection. \ No newline at end of file diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx deleted file mode 100644 index e27434cf..00000000 --- a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/reference/App.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Picker } from '@expo/ui/community/picker' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' - -export default function App() { - const [value, setValue] = useState('expo') - return ( - - - - - - {value} - - ) -} - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml b/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml deleted file mode 100644 index 8e81eea7..00000000 --- a/evals/expo-ui/06-rn-expo-ui-picker-drop-in-import/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: community-picker-import - description: "Must import Picker from @expo/ui/community/picker." - - id: picker-item-children - description: "Must declare options with Picker.Item children." - - id: controlled-selected-value - description: "Must keep selectedValue controlled." - - id: no-react-native-picker-import - description: "Must not import @react-native-picker/picker." diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx deleted file mode 100644 index 54f49d1a..00000000 --- a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo UI slider and segmented control - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md deleted file mode 100644 index 1d465cc1..00000000 --- a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Migrate the slider and segmented control in App.tsx to their Expo UI equivalents. \ No newline at end of file diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx deleted file mode 100644 index 4598f7c4..00000000 --- a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/reference/App.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { Slider } from '@expo/ui/community/slider' -import { SegmentedControl } from '@expo/ui/community/segmented-control' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' - -export default function App() { - const [value, setValue] = useState(40) - const [segment, setSegment] = useState('daily') - const segments = ['daily', 'weekly'] - return ( - - - - {segment}: {Math.round(value)} - - ) -} - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml b/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml deleted file mode 100644 index dc6fc420..00000000 --- a/evals/expo-ui/07-rn-expo-ui-slider-segmented-drop-in/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: community-slider-import - description: "Must import Slider from @expo/ui/community/slider." - - id: community-segmented-import - description: "Must import SegmentedControl from @expo/ui/community/segmented-control." - - id: controlled-values - description: "Must keep slider and segmented values controlled by state." - - id: no-legacy-community-control-imports - description: "Must not import legacy community slider or segmented-control packages." diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx deleted file mode 100644 index 23261fd5..00000000 --- a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/app/App.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Expo UI menu and masked view - Replace this scaffold with the requested Expo implementation. - - Start - - - ) -} - -const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, -}) diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md deleted file mode 100644 index d5492814..00000000 --- a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Migrate the context menu and masked view in App.tsx to their Expo UI equivalents. \ No newline at end of file diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx deleted file mode 100644 index 7d3ce9f8..00000000 --- a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/reference/App.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { MaskedView } from '@expo/ui/community/masked-view' -import { MenuView } from '@expo/ui/community/menu' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' - -export default function App() { - const [message, setMessage] = useState('No action.') - return ( - - setMessage(nativeEvent.event)}> - Open menu - - Mask}> - {message} - - ) -} - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml b/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml deleted file mode 100644 index 8381e170..00000000 --- a/evals/expo-ui/09-rn-expo-ui-menu-maskedview-drop-in/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: community-menu-import - description: "Must import MenuView from @expo/ui/community/menu." - - id: community-masked-view-import - description: "Must import MaskedView from @expo/ui/community/masked-view." - - id: deterministic-menu-actions - description: "Must define deterministic menu action ids/titles and handle selected action." - - id: no-legacy-menu-masked-imports - description: "Must not import legacy menu or masked-view community packages directly." From c8d7c4b804bdef9d0374beb30d908c9edf543182 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 00:39:57 +0400 Subject: [PATCH 13/32] refactor(evals): reseed Expo starter templates with realistic baselines Replace the uniform "Replace this scaffold" placeholder used across all Expo starters with task-specific baselines that follow the repo methodology (app/ = realistic code the solver extends), matching the convention in animation/async-state/navigation/lists evals. - Migrate evals seed working legacy code (e.g. @gorhom/bottom-sheet, react-native-pager-view, @react-navigation, deprecated FileSystem and video-thumbnails APIs) so no-legacy-import requirements are meaningful - "Broken after upgrade / not picked up" evals seed the actual defect (e.g. Swift module name mismatch, crashing root FileSystem calls) - "Add X" evals seed the surrounding screen with stubbed handlers - Greenfield evals seed a real default app screen, never instruction text - expo-modules/07 gains package.json so the missing-types task is fixable Co-Authored-By: Claude Opus 4.6 --- .../app/App.tsx | 44 +++---- .../app/INLINE_MODULES.md | 7 +- .../app/src/modules/DeviceAuditModule.kt | 16 ++- .../app/App.tsx | 37 +++--- .../app/index.ts | 4 +- .../app/modules/WeatherInlineModule.swift | 14 ++- .../app/App.tsx | 39 ++++--- .../app/src/NativeDeviceAudit.ts | 6 +- .../app/src/index.ts | 2 +- .../app/App.tsx | 35 +++--- .../app/ios/AuditLabelModule.swift | 6 +- .../app/ios/AuditLabelView.swift | 15 ++- .../app/src/AuditLabel.tsx | 8 +- .../app/App.tsx | 38 +++---- .../app/build/index.d.ts | 2 +- .../app/package.json | 18 +++ .../app/src/index.ts | 8 +- .../requirements.yaml | 1 + .../app/App.tsx | 29 ++--- .../app/app.config.ts | 12 +- .../app/plugin/withAuditPermissions.ts | 8 +- .../app/App.tsx | 37 +++--- .../app/_layout.tsx | 15 ++- .../app/_layout.tsx | 4 +- .../app/index.tsx | 13 ++- .../app/_layout.tsx | 8 +- .../app/index.tsx | 14 ++- .../app/_layout.tsx | 8 +- .../app/index.tsx | 17 ++- .../app/_layout.tsx | 9 +- .../app/index.tsx | 13 ++- .../app/settings.tsx | 14 +++ .../requirements.yaml | 1 + .../app/_layout.tsx | 13 ++- .../app/index.tsx | 13 ++- .../app/settings.tsx | 14 +++ .../requirements.yaml | 1 + .../app/_layout.tsx | 11 +- .../app/account.tsx | 15 +++ .../app/index.tsx | 14 ++- .../app/sign-in.tsx | 17 +++ .../requirements.yaml | 2 + .../app/_layout.tsx | 9 +- .../app/details.tsx | 15 +++ .../app/index.tsx | 15 ++- .../requirements.yaml | 1 + .../app/_layout.tsx | 4 +- .../app/index.tsx | 13 ++- .../app/_layout.tsx | 4 +- .../app/index.tsx | 13 ++- .../app/profile.tsx | 4 +- .../app/server/profile.server.ts | 2 +- .../app/_layout.tsx | 4 +- .../app/index.tsx | 9 +- .../app/+not-found.tsx | 8 +- .../app/[...slug].tsx | 11 +- .../app/_layout.tsx | 4 +- .../app/index.tsx | 13 ++- .../app/App.tsx | 56 +++++++-- .../app/App.tsx | 68 ++++++++--- .../app/App.tsx | 83 +++++++++++--- .../app/App.tsx | 52 ++++++--- .../app/App.tsx | 48 +++++--- .../app/App.tsx | 60 +++++++--- .../app/App.tsx | 64 +++++++---- .../app/App.tsx | 57 ++++++++-- .../app/App.tsx | 48 +++++--- .../app/App.tsx | 72 ++++++++---- .../app/App.tsx | 23 ++-- .../app/App.tsx | 59 ++++++++-- .../app/App.tsx | 56 ++++++--- .../app/App.tsx | 68 +++++++++-- .../app/App.tsx | 59 +++++++--- .../app/App.tsx | 58 ++++++++-- .../app/App.tsx | 106 +++++++++++++++-- .../app/App.tsx | 107 ++++++++++++++++-- .../app/App.tsx | 53 +++++++-- .../21-rn-expo-video-player-view/app/App.tsx | 85 ++++++++++---- .../app/App.tsx | 53 ++++++--- .../app/App.tsx | 55 ++++++--- .../app/App.tsx | 82 ++++++++++---- .../app/App.tsx | 73 ++++++++---- .../app/App.tsx | 26 ++--- .../app/App.tsx | 51 +++++---- .../app/App.tsx | 57 ++++++---- .../app/App.tsx | 46 +++++--- .../app/App.tsx | 66 +++++++---- .../app/App.tsx | 81 +++++++++---- .../app/App.tsx | 69 +++++++---- .../app/App.tsx | 53 ++++----- .../app/App.tsx | 49 ++++---- .../app/App.tsx | 57 ++++++---- 92 files changed, 2054 insertions(+), 777 deletions(-) create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json create mode 100644 evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/settings.tsx create mode 100644 evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/settings.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/app/account.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx create mode 100644 evals/expo-router/08-rn-expo-router-serializable-search-params/app/details.tsx diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx index 01503660..eca68eb4 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx @@ -1,28 +1,33 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { requireNativeModule } from 'expo' +import { StyleSheet, Text, View } from 'react-native' + +type DeviceAuditModule = { + source: string + getOsVersion(): string +} + +let osVersion = 'unknown' +let source = 'unavailable' + +try { + const DeviceAudit = requireNativeModule('DeviceAuditModule') + osVersion = DeviceAudit.getOsVersion() + source = DeviceAudit.source +} catch { + // Native module is not registered with the current build yet. +} export default function App() { return ( - Expo Modules 1 - Replace this scaffold with the requested Expo implementation. - - Start - + Device Audit + OS version: {osVersion} + Module source: {source} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +36,13 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + row: { + color: '#374151', + }, }) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md index 66ce1cf2..e3549c43 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md @@ -1,3 +1,8 @@ # Inline Modules -Add any build or prebuild notes for inline module config changes here. +Native modules under `src/` are written with the Expo Modules Kotlin/Swift DSL so +they can be picked up as inline modules without publishing a separate package. + +Changes to the inline module configuration require regenerating the native project +(`npx expo prebuild`) or rebuilding the development client so the generated module +providers include the inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt index 8578ba71..808e1bf1 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt @@ -1,3 +1,17 @@ package expo.modules.deviceaudit -// Replace with an Expo ModuleDefinition inline module. +import android.os.Build +import expo.modules.kotlin.modules.Module +import expo.modules.kotlin.modules.ModuleDefinition + +class DeviceAuditModule : Module() { + override fun definition() = ModuleDefinition { + Name("DeviceAuditModule") + + Constant("source") { "inline" } + + Function("getOsVersion") { + Build.VERSION.RELEASE + } + } +} diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx index 00b8b5e4..4360f08c 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx @@ -1,28 +1,25 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +import { WeatherInlineModule } from './index' + +let unit = 'unavailable' + +try { + unit = WeatherInlineModule.unit() +} catch { + // The native module did not load under the requested name. +} export default function App() { return ( - Expo Modules 3 - Replace this scaffold with the requested Expo implementation. - - Start - + Weather + Temperature unit: {unit} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +28,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, }) diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts index 47a4aea8..942fed50 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts @@ -1 +1,3 @@ -// Export the inline Swift module wrapper from here. +import { requireNativeModule } from 'expo-modules-core' + +export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift index c30d2df0..d15a2f3f 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift @@ -1,3 +1,15 @@ import ExpoModulesCore -// Replace with a Swift inline module whose file, class, and Name match. +public class WeatherModule: Module { + public func definition() -> ModuleDefinition { + Name("WeatherModule") + + Function("unit") { + return "celsius" + } + + Function("currentTemperature") { + return 21 + } + } +} diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx index b00f2f48..d6daad5b 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx @@ -1,28 +1,27 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' + +import { DeviceAudit } from './src' export default function App() { + const [battery, setBattery] = useState('loading…') + + useEffect(() => { + // No types here, so this call site is unchecked. + DeviceAudit.getBatteryLabelAsync() + .then((label: string) => setBattery(label)) + .catch(() => setBattery('unavailable')) + }, []) + return ( - Expo Modules 5 - Replace this scaffold with the requested Expo implementation. - - Start - + Device Audit + Battery: {battery} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +30,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, }) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts index 532936e2..7c564109 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts @@ -1 +1,5 @@ -// Wrap the native module with requireNativeModule and export typed helpers. +import { NativeModulesProxy } from 'expo-modules-core' + +// Untyped access to the native module. Consumers reach into this proxy +// directly, so there is no type safety on the function surface. +export const DeviceAudit = NativeModulesProxy.DeviceAudit diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts index cb46f69e..83b0eb08 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts @@ -1 +1 @@ -// Re-export the public JS helper from here. +export { DeviceAudit } from './NativeDeviceAudit' diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx index e86b33f3..6798f6b7 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx @@ -1,28 +1,23 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +import AuditLabel from './src/AuditLabel' export default function App() { return ( - Expo Modules 6 - Replace this scaffold with the requested Expo implementation. - - Start - + Audit Label + { + console.log('AuditLabel is ready') + }} + style={styles.label} + /> ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +26,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + label: { + height: 44, + width: 200, + }, }) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift index 155a9093..d350a43f 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift @@ -1,3 +1,7 @@ import ExpoModulesCore -// Define the native module and its View(...) declaration here. +public class AuditLabelModule: Module { + public func definition() -> ModuleDefinition { + Name("AuditLabel") + } +} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift index 8ed87882..d6a17e12 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift @@ -1,3 +1,16 @@ import ExpoModulesCore -// Define the ExpoView subclass used by the module. +final class AuditLabelView: ExpoView { + let label = UILabel() + + required init(appContext: AppContext? = nil) { + super.init(appContext: appContext) + label.numberOfLines = 0 + addSubview(label) + } + + override func layoutSubviews() { + super.layoutSubviews() + label.frame = bounds + } +} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx index beaa7ac0..91fd0a5b 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx @@ -1 +1,7 @@ -// Wrap the native view manager and expose typed props/events. +import { requireNativeViewManager } from 'expo-modules-core' + +// Minimal native view wrapper. Props and events are not yet typed or +// forwarded from the native module definition. +const NativeAuditLabel = requireNativeViewManager('AuditLabel') + +export default NativeAuditLabel diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx index d0f16e38..b6f514f3 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx @@ -1,28 +1,26 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' + +import { audit, type AuditResult } from './src' export default function App() { + const [result, setResult] = useState(null) + + useEffect(() => { + audit().then(setResult) + }, []) + return ( - Expo Modules 7 - Replace this scaffold with the requested Expo implementation. - - Start - + Audit + + Status: {result ? (result.ok ? 'ok' : 'failed') : 'running…'} + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +29,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, }) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts index 9033df27..620533ae 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts @@ -1 +1 @@ -// Commit generated public TypeScript declarations here. +export declare function audit(): Promise diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json new file mode 100644 index 00000000..9fda2c4f --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json @@ -0,0 +1,18 @@ +{ + "name": "expo-audit", + "version": "1.0.0", + "main": "build/index.js", + "types": ".typegen-tmp/index.d.ts", + "files": [ + "src", + "expo-module.config.json" + ], + "scripts": { + "build": "expo-module build", + "typegen": "tsc --emitDeclarationOnly --outDir .typegen-tmp" + }, + "devDependencies": { + "expo-module-scripts": "^4.0.0", + "typescript": "^5.3.0" + } +} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts index 83716f6c..4d049abc 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts @@ -1 +1,7 @@ -// Export public runtime helpers and public TypeScript types from here. +export type AuditResult = { + ok: boolean +} + +export async function audit(): Promise { + return { ok: true } +} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml index 6523b180..601aa1cf 100644 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml @@ -4,6 +4,7 @@ inputs: - app/App.tsx - app/build/index.d.ts - app/expo-module.config.json + - app/package.json - app/src/index.ts requirements: - id: expo-module-config-platforms diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx index 16649b59..27b0b48d 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx @@ -1,28 +1,17 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( - Expo Modules 8 - Replace this scaffold with the requested Expo implementation. - - Start - + Audit + + Camera access is required to run a device audit. + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +20,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, }) diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts index 607d4885..9d852b79 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts @@ -1,5 +1,9 @@ -export default { - expo: { - plugins: [], - }, +import { ExpoConfig } from 'expo/config' + +const config: ExpoConfig = { + name: 'audit', + slug: 'audit', + plugins: [], } + +export default config diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts index a94a94f6..ab02eb4c 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts @@ -1 +1,7 @@ -// Export a ConfigPlugin that writes iOS and Android permission config. +import { ConfigPlugin } from 'expo/config-plugins' + +export const withAuditPermissions: ConfigPlugin = (config) => { + return config +} + +export default withAuditPermissions diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx index e6fa0071..fe6a0653 100644 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx @@ -1,28 +1,25 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +import { getPlatform } from './src' + +let platform = 'unknown' + +try { + platform = getPlatform() +} catch { + // No implementation is registered for the current platform. +} export default function App() { return ( - Expo Modules 10 - Replace this scaffold with the requested Expo implementation. - - Start - + Audit + Running on: {platform} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +28,14 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, }) diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx index cb1576d3..59f398e3 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx @@ -1,5 +1,16 @@ -import { Text } from 'react-native' +import { DefaultTheme, ThemeProvider, useNavigation } from '@react-navigation/native' +import { createNativeStackNavigator } from '@react-navigation/native-stack' + +const Stack = createNativeStackNavigator() export default function Layout() { - return Replace with Expo Router layout. + useNavigation() + + return ( + + + + + + ) } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx index cb1576d3..3d271a62 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/_layout.tsx @@ -1,5 +1,5 @@ -import { Text } from 'react-native' +import { Slot } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx index 66f93c34..194b87ed 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx @@ -1,9 +1,16 @@ -import { Text, View } from 'react-native' +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home + + Products + View details ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx index cb1576d3..9b13dcb9 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx @@ -1,5 +1,9 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return ( + + + + ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx index 66f93c34..64e1d950 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx @@ -1,9 +1,17 @@ -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { + const handleCreate = () => {} + return ( - - Home + + Inbox + Tap the header action to add a new item. ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx index cb1576d3..2bacf4ee 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/_layout.tsx @@ -1,5 +1,9 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return ( + + + + ) } diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx index 66f93c34..e3a786da 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/app/index.tsx @@ -1,9 +1,20 @@ -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +const ITEMS = Array.from({ length: 20 }, (_, i) => `Activity ${i + 1}`) export default function Index() { return ( - - Home + + {ITEMS.map((item) => ( + + {item} + + ))} ) } + +const styles = StyleSheet.create({ + container: { padding: 16, gap: 8 }, + row: { fontSize: 16 }, +}) diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx index cb1576d3..44d98837 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/_layout.tsx @@ -1,5 +1,10 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return ( + + + + + ) } diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx index 66f93c34..87a7a2cd 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/index.tsx @@ -1,9 +1,14 @@ -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' -export default function Index() { +export default function Home() { return ( - - Home + + Home ) } + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/settings.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/settings.tsx new file mode 100644 index 00000000..fcc1d19a --- /dev/null +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/app/settings.tsx @@ -0,0 +1,14 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Settings() { + return ( + + Settings + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml index 95b40fcd..4794eb48 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/requirements.yaml @@ -3,6 +3,7 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/settings.tsx requirements: - id: imports-unstable-native-tabs description: "Must import NativeTabs from expo-router/unstable-native-tabs." diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx index cb1576d3..253148fd 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/_layout.tsx @@ -1,5 +1,14 @@ -import { Text } from 'react-native' +import { NativeTabs } from 'expo-router/unstable-native-tabs' export default function Layout() { - return Replace with Expo Router layout. + return ( + + + Home + + + Settings + + + ) } diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx index 66f93c34..87a7a2cd 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/index.tsx @@ -1,9 +1,14 @@ -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' -export default function Index() { +export default function Home() { return ( - - Home + + Home ) } + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/settings.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/settings.tsx new file mode 100644 index 00000000..fcc1d19a --- /dev/null +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/app/settings.tsx @@ -0,0 +1,14 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Settings() { + return ( + + Settings + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml index 1c6c392b..ef527f4a 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml @@ -3,6 +3,7 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/settings.tsx requirements: - id: selected-default-icon-state description: "Must configure selected/default icon or label state through NativeTabs.Trigger children." diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx index cb1576d3..093b2f99 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/_layout.tsx @@ -1,5 +1,12 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' + +const signedIn = false export default function Layout() { - return Replace with Expo Router layout. + return ( + + + + + ) } diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/account.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/account.tsx new file mode 100644 index 00000000..5090e3ba --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/account.tsx @@ -0,0 +1,15 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Account() { + return ( + + Account + Signed-in profile details. + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx index 66f93c34..96a6b777 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/index.tsx @@ -1,9 +1,17 @@ -import { Text, View } from 'react-native' +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home + + Welcome + Account + Sign in ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx new file mode 100644 index 00000000..61725131 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx @@ -0,0 +1,17 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function SignIn() { + const handleSignIn = () => {} + + return ( + + Sign in + Authenticate to access your account. + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml index 1f4c6b6e..66e66844 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -3,6 +3,8 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/account.tsx + - app/sign-in.tsx requirements: - id: uses-protected-routes description: "Must use Stack.Protected, Tabs.Protected, or the Expo Router protected route API." diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx index cb1576d3..57ccc1dd 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/_layout.tsx @@ -1,5 +1,10 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return ( + + + + + ) } diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/details.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/details.tsx new file mode 100644 index 00000000..a9cad0de --- /dev/null +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/details.tsx @@ -0,0 +1,15 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Details() { + return ( + + Details + Product — + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx index 66f93c34..a6a09086 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/app/index.tsx @@ -1,9 +1,18 @@ -import { Text, View } from 'react-native' +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' + +const PRODUCT = { id: '42', tab: 'overview' } export default function Index() { return ( - - Home + + Products + Open details ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml index 10664192..c7c49800 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml @@ -3,6 +3,7 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/details.tsx requirements: - id: serializable-link-params description: "Must navigate with serializable primitive search params." diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx index cb1576d3..99996670 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx @@ -1,5 +1,5 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return } diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx index 66f93c34..575c1c3d 100644 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx +++ b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx @@ -1,9 +1,20 @@ +import { useEffect, useState } from 'react' import { Text, View } from 'react-native' +async function fetchGreeting() { + return { greeting: 'Loaded on the route boundary' } +} + export default function Index() { + const [data, setData] = useState<{ greeting: string } | null>(null) + + useEffect(() => { + fetchGreeting().then(setData) + }, []) + return ( - Home + {data?.greeting ?? 'Loading...'} ) } diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx index cb1576d3..99996670 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx @@ -1,5 +1,5 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return } diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx index 66f93c34..b341b6ea 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx @@ -1,9 +1,16 @@ -import { Text, View } from 'react-native' +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home + + Home + View profile ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx index c06a0dfd..f352d9b4 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx @@ -1,5 +1,7 @@ import { Text } from 'react-native' export default function Profile() { - return Profile + const name = process.env.PROFILE_NAME ?? 'Expo' + + return {name} } diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts index 7861e23c..5a6cd4e6 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts @@ -1,3 +1,3 @@ export async function getProfile() { - return {} + return { name: process.env.PROFILE_NAME ?? 'Expo' } } diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx index cb1576d3..99996670 100644 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx @@ -1,5 +1,5 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return } diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx index 66f93c34..be53b8ce 100644 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx @@ -1,9 +1,16 @@ +import { use } from 'react' import { Text, View } from 'react-native' +const contentPromise = new Promise((resolve) => + setTimeout(() => resolve('Async route content'), 500), +) + export default function Index() { + const content = use(contentPromise) + return ( - Home + {content} ) } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx index 12a76b95..802a728b 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx @@ -1,5 +1,9 @@ -import { Text } from 'react-native' +import { Text, View } from 'react-native' export default function NotFound() { - return Not Found + return ( + + Not found + + ) } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx index 464e5359..645b9c16 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx @@ -1,5 +1,12 @@ -import { Text } from 'react-native' +import { useLocalSearchParams } from 'expo-router' +import { Text, View } from 'react-native' export default function CatchAll() { - return Catch All + const { slug } = useLocalSearchParams<{ slug?: string[] }>() + + return ( + + Docs: {slug?.join('/') ?? 'index'} + + ) } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx index cb1576d3..99996670 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx @@ -1,5 +1,5 @@ -import { Text } from 'react-native' +import { Stack } from 'expo-router' export default function Layout() { - return Replace with Expo Router layout. + return } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx index 66f93c34..b6da9453 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx @@ -1,9 +1,16 @@ -import { Text, View } from 'react-native' +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home + + Home + Docs ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx index a9f996af..146036c0 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx @@ -1,13 +1,35 @@ import { Pressable, StyleSheet, Text, View } from 'react-native' +type PermissionState = 'undetermined' | 'granted' | 'denied' + export default function App() { + const permissionState: PermissionState = 'undetermined' + + const handleRequestPermission = () => {} + const handleOpenSettings = () => {} + return ( - Camera permission retry - Replace this scaffold with the requested Expo implementation. - - Start - + Camera + + + Camera is off + + + {permissionState === 'denied' ? ( + + + Camera access is turned off. Enable it in Settings to continue. + + + Open Settings + + + ) : ( + + Enable Camera + + )} ) } @@ -22,23 +44,37 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - screen: { + preview: { alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', + borderRadius: 12, + justifyContent: 'center', + width: '100%', + }, + previewText: { + color: '#9ca3af', + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, + rowGap: 16, + }, + statusBlock: { + alignItems: 'center', rowGap: 10, }, - subtitle: { + statusText: { color: '#6b7280', textAlign: 'center', }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx index 600aafa7..a0f39dd7 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx @@ -1,12 +1,34 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' export default function App() { + const [cameraEnabled, setCameraEnabled] = useState(true) + + const handleTakePhoto = () => {} + return ( - Camera active lifecycle - Replace this scaffold with the requested Expo implementation. - - Start + Camera Preview + + + {cameraEnabled ? ( + Live preview + ) : ( + Camera paused + )} + + + + Camera enabled + + + + + Take Photo ) @@ -19,26 +41,44 @@ const styles = StyleSheet.create({ paddingHorizontal: 14, paddingVertical: 10, }, + buttonDisabled: { + backgroundColor: '#9ca3af', + }, buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - screen: { + preview: { + alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', + borderRadius: 12, + justifyContent: 'center', + width: '100%', + }, + previewText: { + color: '#9ca3af', + }, + row: { alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx index 126173d9..d2df74e2 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx @@ -1,12 +1,33 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' export default function App() { + const [recordAudio, setRecordAudio] = useState(false) + const [lastScan, setLastScan] = useState(null) + + const handleStartRecording = () => {} + return ( - Camera barcode and audio - Replace this scaffold with the requested Expo implementation. - - Start + Scanner + + + + Point at a barcode + + + + Last scan + {lastScan ?? '—'} + + + + Record audio + + + + + Record Video ) @@ -22,23 +43,57 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - screen: { + preview: { + alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', + borderRadius: 12, + justifyContent: 'center', + rowGap: 12, + width: '100%', + }, + previewText: { + color: '#9ca3af', + }, + resultLabel: { + color: '#6b7280', + }, + resultRow: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + resultValue: { + color: '#111827', + fontWeight: '600', + }, + row: { alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, + scanFrame: { + borderColor: '#22c55e', + borderRadius: 8, + borderWidth: 2, + height: 120, + width: 180, + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx index e5edae59..56ad2c73 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/app/App.tsx @@ -1,12 +1,25 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const [imageUri, setImageUri] = useState(null) + + const handlePickImage = () => {} + return ( - ImagePicker canceled guard - Replace this scaffold with the requested Expo implementation. - - Start + Profile Photo + + + {imageUri ? ( + + ) : ( + No image selected + )} + + + + Choose from Library ) @@ -22,23 +35,34 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - screen: { + image: { + height: '100%', + width: '100%', + }, + preview: { alignItems: 'center', + aspectRatio: 1, + backgroundColor: '#f3f4f6', + borderRadius: 12, + justifyContent: 'center', + overflow: 'hidden', + width: '100%', + }, + previewText: { + color: '#9ca3af', + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx index 99be2f5d..77ee57e8 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/app/App.tsx @@ -1,12 +1,27 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const [videoUri, setVideoUri] = useState(null) + + const handlePickVideo = () => {} + return ( - ImagePicker video permission nuance - Replace this scaffold with the requested Expo implementation. - - Start + Upload Video + + + {videoUri ? ( + + {videoUri} + + ) : ( + No video selected + )} + + + + Choose Video ) @@ -22,23 +37,30 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - screen: { + preview: { alignItems: 'center', + aspectRatio: 16 / 9, + backgroundColor: '#111827', + borderRadius: 12, + justifyContent: 'center', + paddingHorizontal: 12, + width: '100%', + }, + previewText: { + color: '#9ca3af', + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx index 8d53609d..10a18d1e 100644 --- a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/app/App.tsx @@ -1,12 +1,35 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +type Coordinates = { + latitude: number + longitude: number +} + export default function App() { + const [coords, setCoords] = useState(null) + const [address, setAddress] = useState(null) + + const handleFindLocation = () => {} + return ( - Location geocode guard - Replace this scaffold with the requested Expo implementation. - - Start + Where am I? + + + Coordinates + + {coords + ? `${coords.latitude.toFixed(5)}, ${coords.longitude.toFixed(5)}` + : 'Unknown'} + + + Address + {address ?? 'Unknown'} + + + + Find My Location ) @@ -22,23 +45,34 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', + }, + card: { + backgroundColor: '#f3f4f6', + borderRadius: 12, + padding: 16, + rowGap: 6, + }, + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 16, + fontWeight: '600', + marginBottom: 6, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx index 46d20e68..2bacde72 100644 --- a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/app/App.tsx @@ -1,44 +1,64 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' export default function App() { + const [tracking, setTracking] = useState(false) + const [lastUpdate, setLastUpdate] = useState(null) + + const handleToggleTracking = () => {} + return ( - Background location permission order - Replace this scaffold with the requested Expo implementation. - - Start - + Trip Tracking + + + Last update + {lastUpdate ?? 'No updates yet'} + + + + Track in background + + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + card: { + backgroundColor: '#f3f4f6', + borderRadius: 12, + padding: 16, + rowGap: 6, }, - buttonText: { - color: '#fff', + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 16, fontWeight: '600', }, - screen: { + row: { alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, + screen: { backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx index 85fc4b00..585cdbcf 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/app/App.tsx @@ -1,12 +1,32 @@ import { Pressable, StyleSheet, Text, View } from 'react-native' +type PermissionStatus = 'undetermined' | 'granted' | 'denied' + export default function App() { + const permissionStatus: PermissionStatus = 'undetermined' + const preciseAccuracy = false + + const handleRefresh = () => {} + return ( - Location accuracy authorization - Replace this scaffold with the requested Expo implementation. - - Start + Location Status + + + + Permission + {permissionStatus} + + + Accuracy + + {preciseAccuracy ? 'Precise' : 'Approximate'} + + + + + + Refresh Status ) @@ -22,23 +42,38 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', + }, + card: { + backgroundColor: '#f3f4f6', + borderRadius: 12, + padding: 16, + rowGap: 12, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 16, }, - subtitle: { + statusLabel: { color: '#6b7280', - textAlign: 'center', + fontSize: 15, }, - title: { + statusRow: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + statusValue: { color: '#111827', - fontSize: 20, + fontSize: 15, fontWeight: '600', - textAlign: 'center', + textTransform: 'capitalize', + }, + title: { + color: '#111827', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx index 581b565f..689cf853 100644 --- a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/app/App.tsx @@ -1,12 +1,24 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const [pushToken, setPushToken] = useState(null) + + const handleRegister = () => {} + return ( - Notifications channel and token - Replace this scaffold with the requested Expo implementation. - - Start + Push Notifications + + + Expo push token + + {pushToken ?? 'Not registered'} + + + + + Register for Notifications ) @@ -22,23 +34,33 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', + }, + card: { + backgroundColor: '#f3f4f6', + borderRadius: 12, + padding: 16, + rowGap: 6, + }, + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 14, + fontWeight: '600', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx index 2a22acd9..b60066fe 100644 --- a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/app/App.tsx @@ -1,44 +1,70 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { FlatList, StyleSheet, Text, View } from 'react-native' + +type InboxItem = { + id: string + title: string + body: string + tapped: boolean +} export default function App() { + // Populated from incoming notifications and tap events. + const items: InboxItem[] = [] + return ( - Notifications listener cleanup - Replace this scaffold with the requested Expo implementation. - - Start - + Inbox + + item.id} + ListEmptyComponent={ + No notifications yet. + } + renderItem={({ item }) => ( + + {item.title} + {item.body} + + )} + /> ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', + empty: { + color: '#9ca3af', + marginTop: 24, + textAlign: 'center', + }, + row: { + backgroundColor: '#f3f4f6', borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + marginBottom: 8, + padding: 12, + rowGap: 4, + }, + rowBody: { + color: '#6b7280', }, - buttonText: { - color: '#fff', + rowTapped: { + opacity: 0.6, + }, + rowTitle: { + color: '#111827', fontWeight: '600', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + paddingHorizontal: 20, + paddingTop: 64, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', + marginBottom: 16, }, }) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx index ad6425f5..4a5b242f 100644 --- a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx @@ -1,12 +1,17 @@ import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const handleSendTest = () => {} + return ( - Notifications config - Replace this scaffold with the requested Expo implementation. - - Start + Notifications + + Notification appearance is configured at the native level. + + + + Send Test Notification ) @@ -22,23 +27,21 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx index 1a21020a..76d7c7d6 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx @@ -1,13 +1,44 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' export default function App() { + const [draft, setDraft] = useState('') + const [status, setStatus] = useState('Loading notes…') + + const loadNote = async () => { + // Read the persisted note from the cache file on mount. + setStatus('No saved note yet.') + } + + const saveNote = async () => { + // Persist the current draft to the cache file. + setStatus('Saved.') + } + + useEffect(() => { + void loadNote() + }, []) + return ( - FileSystem object API - Replace this scaffold with the requested Expo implementation. - - Start + Notes + + + Save + {status} ) } @@ -23,22 +54,26 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, + input: { + borderColor: '#d1d5db', + borderRadius: 10, + borderWidth: 1, + minHeight: 120, + padding: 12, + textAlignVertical: 'top', + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, - subtitle: { + status: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx index 10bf6563..3e1a08b6 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx @@ -1,44 +1,74 @@ +import { + cacheDirectory, + makeDirectoryAsync, + readAsStringAsync, + writeAsStringAsync, +} from 'expo-file-system' +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +const PROFILE_DIR = `${cacheDirectory}profile/` +const PROFILE_FILE = `${PROFILE_DIR}profile.json` + export default function App() { + const [message, setMessage] = useState('Ready.') + + const saveProfile = async () => { + try { + await makeDirectoryAsync(PROFILE_DIR, { intermediates: true }) + await writeAsStringAsync(PROFILE_FILE, JSON.stringify({ name: 'Expo' })) + setMessage('Saved profile.') + } catch (error) { + setMessage(`Save failed: ${String(error)}`) + } + } + + const loadProfile = async () => { + try { + const contents = await readAsStringAsync(PROFILE_FILE) + setMessage(contents) + } catch (error) { + setMessage(`Load failed: ${String(error)}`) + } + } + return ( - FileSystem legacy import boundary - Replace this scaffold with the requested Expo implementation. - - Start + Filesystem helper + {message} + + Save profile + + + Load profile ) } const styles = StyleSheet.create({ - button: { + action: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - buttonText: { + actionText: { color: '#fff', fontWeight: '600', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { - color: '#6b7280', - textAlign: 'center', + color: '#4b5563', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx index 3fc651ed..b7a13840 100644 --- a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx @@ -1,12 +1,51 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + ActivityIndicator, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' + +const REMOTE_URL = 'https://example.com/report.pdf' +const UPLOAD_ENDPOINT = 'https://example.com/api/upload' + +type Phase = 'idle' | 'downloading' | 'uploading' | 'done' | 'error' export default function App() { + const [phase, setPhase] = useState('idle') + const [progress, setProgress] = useState(0) + + const transfer = async () => { + setPhase('downloading') + setProgress(0) + // Download REMOTE_URL to local storage, then upload it to UPLOAD_ENDPOINT. + setPhase('done') + } + return ( - FileSystem download upload - Replace this scaffold with the requested Expo implementation. - - Start + Sync report + {REMOTE_URL} + + {phase === 'downloading' || phase === 'uploading' ? ( + + + + {phase === 'downloading' + ? `Downloading ${Math.round(progress * 100)}%` + : 'Uploading…'} + + + ) : null} + + {phase === 'done' ? Upload complete. : null} + {phase === 'error' ? ( + Transfer failed. + ) : null} + + + Download & upload ) @@ -23,22 +62,29 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - screen: { + error: { + color: '#b91c1c', + }, + progressRow: { alignItems: 'center', + columnGap: 10, + flexDirection: 'row', + }, + screen: { backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, + }, + status: { + color: '#4b5563', }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx index e9ac81c9..691e4509 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx @@ -1,12 +1,40 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' + +const GENERATED_IMAGE_URI = 'https://example.com/generated/poster.png' + +type SaveState = 'idle' | 'saving' | 'saved' | 'denied' export default function App() { + const [saveState, setSaveState] = useState('idle') + + const saveToLibrary = async () => { + setSaveState('saving') + // Request write-only photo access and save GENERATED_IMAGE_URI. + setSaveState('saved') + } + return ( - MediaLibrary granular write-only - Replace this scaffold with the requested Expo implementation. - - Start + Save poster + + + + {saveState === 'saved' ? ( + Saved to your photos. + ) : null} + {saveState === 'denied' ? ( + + Photo access is required to save this image. + + ) : null} + + + Save to photos ) @@ -23,22 +51,27 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, + error: { + color: '#b91c1c', + }, + preview: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 220, + width: '100%', + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + status: { + color: '#4b5563', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx index 04edf58c..027078b9 100644 --- a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx @@ -1,12 +1,40 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' + +const ALBUM_NAME = 'My Renders' +const LOCAL_IMAGE_URI = 'file:///tmp/render.png' + +type SaveState = 'idle' | 'saving' | 'saved' | 'error' export default function App() { + const [saveState, setSaveState] = useState('idle') + + const saveToAlbum = async () => { + setSaveState('saving') + // Save LOCAL_IMAGE_URI as an asset and add it to ALBUM_NAME. + setSaveState('saved') + } + return ( - MediaLibrary Asset.create - Replace this scaffold with the requested Expo implementation. - - Start + Save render + Album: {ALBUM_NAME} + + + + {saveState === 'saved' ? ( + Added to {ALBUM_NAME}. + ) : null} + {saveState === 'error' ? ( + Could not save the image. + ) : null} + + + Save to album ) @@ -23,22 +51,30 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, + error: { + color: '#b91c1c', + }, + preview: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 220, + width: '100%', + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, + }, + status: { + color: '#4b5563', }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx index fade8543..d519ee58 100644 --- a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx @@ -1,13 +1,70 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' + +type CalendarOption = { + id: string + title: string +} export default function App() { + const [calendars, setCalendars] = useState([]) + const [selectedId, setSelectedId] = useState(null) + const [eventTitle, setEventTitle] = useState('') + const [status, setStatus] = useState('') + + const loadCalendars = async () => { + // Request calendar permission and load writable calendars. + setStatus('Calendar permission required.') + } + + const createEvent = async () => { + // Create the event on the selected calendar. + setStatus('Event created.') + } + + useEffect(() => { + void loadCalendars() + }, []) + return ( - Calendar current API - Replace this scaffold with the requested Expo implementation. - - Start + New event + + + {calendars.map((calendar) => { + const isActive = calendar.id === selectedId + return ( + setSelectedId(calendar.id)} + style={[styles.chip, isActive && styles.chipActive]} + > + + {calendar.title} + + + ) + })} + + + + + + Create event + + {status ? {status} : null} ) } @@ -23,22 +80,47 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, + calendarRow: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 8, + }, + chip: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + chipActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + chipText: { + color: '#334155', + fontWeight: '600', + }, + chipTextActive: { + color: '#fff', + }, + input: { + borderColor: '#d1d5db', + borderRadius: 10, + borderWidth: 1, + padding: 12, + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, - subtitle: { + status: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx index f81d2132..a5a9140c 100644 --- a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx @@ -1,19 +1,87 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + FlatList, + Image, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' + +type ContactRow = { + id: string + name: string + email?: string + imageUri?: string +} export default function App() { + const [contacts, setContacts] = useState([]) + const [loaded, setLoaded] = useState(false) + const [denied, setDenied] = useState(false) + + const loadContacts = async () => { + // Request contacts permission and query name, email, and image fields. + setLoaded(true) + } + + if (denied) { + return ( + + Contacts + Contacts permission was denied. + + ) + } + return ( - Contacts fields query - Replace this scaffold with the requested Expo implementation. - - Start - + Contacts + + {!loaded ? ( + + Load contacts + + ) : ( + item.id} + ListEmptyComponent={ + No contacts found. + } + renderItem={({ item }) => ( + + {item.imageUri ? ( + + ) : ( + + )} + + {item.name} + {item.email ? ( + {item.email} + ) : null} + + + )} + /> + )} ) } const styles = StyleSheet.create({ + avatar: { + backgroundColor: '#e5e7eb', + borderRadius: 20, + height: 40, + width: 40, + }, + avatarPlaceholder: { + backgroundColor: '#cbd5e1', + }, button: { + alignSelf: 'flex-start', backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, @@ -23,22 +91,39 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - screen: { + centered: { alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 8, + }, + email: { + color: '#6b7280', + }, + name: { + color: '#111827', + fontWeight: '600', + }, + row: { + alignItems: 'center', + columnGap: 12, + flexDirection: 'row', + paddingVertical: 8, + }, + screen: { + backgroundColor: '#fff', + flex: 1, + padding: 20, + rowGap: 12, }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx index 219f15c7..38606ae0 100644 --- a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx @@ -1,12 +1,30 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +const SOUND_URL = 'https://example.com/preview.mp3' + export default function App() { + const [isPlaying, setIsPlaying] = useState(false) + + const togglePlayback = () => { + // Play or pause the audio preview. + setIsPlaying((current) => !current) + } + return ( - Audio player lifecycle - Replace this scaffold with the requested Expo implementation. - - Start + Audio preview + {SOUND_URL} + + + + {isPlaying ? 'Playing' : 'Paused'} + + + + {isPlaying ? 'Pause' : 'Play'} ) @@ -23,22 +41,37 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, + dot: { + borderRadius: 6, + height: 12, + width: 12, + }, + dotIdle: { + backgroundColor: '#cbd5e1', + }, + dotPlaying: { + backgroundColor: '#16a34a', + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, + }, + status: { + color: '#4b5563', + }, + statusRow: { + alignItems: 'center', + columnGap: 8, + flexDirection: 'row', }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx b/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx index c086a53f..bf19f9c3 100644 --- a/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx +++ b/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx @@ -1,44 +1,91 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +const VIDEO_URL = 'https://example.com/clip.mp4' + export default function App() { + const [muted, setMuted] = useState(true) + const [looping, setLooping] = useState(true) + return ( - Video player view - Replace this scaffold with the requested Expo implementation. - - Start - + Video player + + + Video + + + + setMuted((current) => !current)} + > + + {muted ? 'Muted' : 'Sound on'} + + + + setLooping((current) => !current)} + > + + {looping ? 'Looping' : 'No loop'} + + + + + {VIDEO_URL} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', + controls: { + flexDirection: 'row', + gap: 8, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { color: '#6b7280', - textAlign: 'center', + }, + surface: { + alignItems: 'center', + backgroundColor: '#111827', + borderRadius: 12, + height: 200, + justifyContent: 'center', + width: '100%', + }, + surfaceText: { + color: '#9ca3af', }, title: { color: '#111827', fontSize: 20, + fontWeight: '700', + }, + toggle: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + toggleActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + toggleText: { + color: '#334155', fontWeight: '600', - textAlign: 'center', + }, + toggleTextActive: { + color: '#fff', }, }) diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx index dbbae2ad..191ed5de 100644 --- a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx @@ -1,44 +1,69 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import * as VideoThumbnails from 'expo-video-thumbnails' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' + +const VIDEO_URL = 'https://example.com/demo.mp4' export default function App() { + const [thumbnailUri, setThumbnailUri] = useState(null) + const [message, setMessage] = useState('No thumbnail.') + + const generate = async () => { + try { + const { uri } = await VideoThumbnails.getThumbnailAsync(VIDEO_URL, { + time: 1000, + }) + setThumbnailUri(uri) + setMessage('Generated thumbnail.') + } catch (error) { + setMessage(`Failed: ${String(error)}`) + } + } + return ( - Video thumbnail replacement - Replace this scaffold with the requested Expo implementation. - - Start + Thumbnail + {thumbnailUri ? ( + + ) : ( + {message} + )} + + Generate ) } const styles = StyleSheet.create({ - button: { + action: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - buttonText: { + actionText: { color: '#fff', fontWeight: '600', }, + media: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 180, + width: '100%', + }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { - color: '#6b7280', - textAlign: 'center', + color: '#4b5563', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx index 16bcd0d8..7397e993 100644 --- a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx @@ -1,12 +1,40 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + ActivityIndicator, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' export default function App() { + const [status, setStatus] = useState('Up to date.') + + const checkForUpdate = async () => { + // Check for an available update, download it, and apply it. + setStatus('Checking…') + } + + const isDownloading = false + const downloadProgress = 0 + return ( - Updates progress reload screen - Replace this scaffold with the requested Expo implementation. - - Start + App updates + + {isDownloading ? ( + + + + Downloading {Math.round(downloadProgress * 100)}% + + + ) : ( + {status} + )} + + + Check for updates ) @@ -23,22 +51,23 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - screen: { + progressRow: { alignItems: 'center', + columnGap: 10, + flexDirection: 'row', + }, + screen: { backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + status: { + color: '#4b5563', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx b/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx index 0cbae076..5f9b3b30 100644 --- a/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx @@ -1,44 +1,88 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +const CHANNELS = ['production', 'staging', 'beta'] as const + +type Channel = (typeof CHANNELS)[number] + export default function App() { + const [channel, setChannel] = useState('production') + const [status, setStatus] = useState('') + + const selectChannel = async (next: Channel) => { + setChannel(next) + // Apply the channel selection and check for updates from it. + setStatus(`Checking ${next}…`) + } + return ( - Updates request headers - Replace this scaffold with the requested Expo implementation. - - Start - + Release channel + + + {CHANNELS.map((option) => { + const isActive = option === channel + return ( + selectChannel(option)} + style={[styles.chip, isActive && styles.chipActive]} + > + + {option} + + + ) + })} + + + Active channel: {channel} + {status ? {status} : null} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + channelRow: { + flexDirection: 'row', + gap: 8, }, - buttonText: { - color: '#fff', + chip: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + chipActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + chipText: { + color: '#334155', fontWeight: '600', + textTransform: 'capitalize', + }, + chipTextActive: { + color: '#fff', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, - subtitle: { + status: { color: '#6b7280', - textAlign: 'center', + }, + subtitle: { + color: '#4b5563', }, title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx index eab9b9aa..157dd4bc 100644 --- a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx @@ -1,44 +1,79 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' +type BarStyle = 'light' | 'dark' + export default function App() { + const [barStyle, setBarStyle] = useState('dark') + const [glass, setGlass] = useState(false) + return ( - Status and navigation bars - Replace this scaffold with the requested Expo implementation. - - Start - + Appearance + + + + setBarStyle((current) => (current === 'dark' ? 'light' : 'dark')) + } + > + Bar style: {barStyle} + + + setGlass((current) => !current)} + > + + {glass ? 'Glass on' : 'Glass off'} + + + + + + Controls the system status and navigation bars. + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', + controls: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 8, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', fontSize: 20, + fontWeight: '700', + }, + toggle: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + toggleActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + toggleText: { + color: '#334155', fontWeight: '600', - textAlign: 'center', + }, + toggleTextActive: { + color: '#fff', }, }) diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx index d075ec12..931c71c5 100644 --- a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx @@ -1,35 +1,24 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( - Build properties - Replace this scaffold with the requested Expo implementation. - - Start - + Build properties audit + + Native build configuration is managed in app.config.ts. + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 8, }, subtitle: { color: '#6b7280', @@ -38,7 +27,6 @@ const styles = StyleSheet.create({ title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx index a89cc532..df5d8056 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx @@ -1,44 +1,49 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( - Expo UI universal Host - Replace this scaffold with the requested Expo implementation. - - Start - + Account + + Signed in as + jordan@example.com + + Manage your profile and notification settings. ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + card: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + padding: 16, + rowGap: 4, + width: '100%', }, - buttonText: { - color: '#fff', - fontWeight: '600', + hint: { + color: '#6b7280', + }, + label: { + color: '#6b7280', + fontSize: 13, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, + fontWeight: '700', + }, + value: { + color: '#111827', + fontSize: 16, fontWeight: '600', - textAlign: 'center', }, }) diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx index 3fef911c..8337e8ae 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx @@ -1,44 +1,53 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { StyleSheet, Switch, Text, View } from 'react-native' export default function App() { + const [pushEnabled, setPushEnabled] = useState(true) + const [emailEnabled, setEmailEnabled] = useState(false) + return ( - Expo UI layout controls - Replace this scaffold with the requested Expo implementation. - - Start - + Notifications + + + Push notifications + + + + + Email updates + + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + row: { + alignItems: 'center', + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', + borderRadius: 12, + borderWidth: 1, + flexDirection: 'row', + justifyContent: 'space-between', + paddingHorizontal: 16, + paddingVertical: 12, }, - buttonText: { - color: '#fff', - fontWeight: '600', + rowLabel: { + color: '#111827', + fontSize: 16, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 12, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', + marginBottom: 4, }, }) diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx index a15a6f02..a03e7f35 100644 --- a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx @@ -1,44 +1,62 @@ +import BottomSheet, { BottomSheetView } from '@gorhom/bottom-sheet' +import { useRef } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const sheetRef = useRef(null) + return ( - Expo UI bottom sheet - Replace this scaffold with the requested Expo implementation. - - Start + Trip details + sheetRef.current?.expand()} + style={styles.action} + > + Show summary + + + + Summary + 3 nights · 2 guests · $640 total + + ) } const styles = StyleSheet.create({ - button: { + action: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - buttonText: { + actionText: { color: '#fff', fontWeight: '600', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, + }, + sheetContent: { + padding: 20, + rowGap: 6, + }, + sheetTitle: { + color: '#111827', + fontSize: 18, + fontWeight: '700', }, subtitle: { - color: '#6b7280', - textAlign: 'center', + color: '#4b5563', }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx index 92fed504..018c3ec4 100644 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx @@ -1,44 +1,64 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { + const [name, setName] = useState('') + const [date, setDate] = useState(new Date()) + + const handlePickDate = () => {} + return ( - Expo UI DateTimePicker open API trap - Replace this scaffold with the requested Expo implementation. - - Start - + New reservation + + + Guest name + + + + + Date + + {date.toDateString()} + + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', + field: { + rowGap: 6, + }, + input: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 12, }, - buttonText: { - color: '#fff', - fontWeight: '600', + inputText: { + color: '#111827', + }, + label: { + color: '#6b7280', + fontSize: 13, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx index 94a74f6b..281b0d66 100644 --- a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx @@ -1,44 +1,79 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { + const [title, setTitle] = useState('') + const [startsAt, setStartsAt] = useState(new Date()) + + const handlePickDate = () => {} + const handlePickTime = () => {} + return ( - Expo UI DateTimePicker supported props - Replace this scaffold with the requested Expo implementation. - - Start - + New appointment + + + Title + + + + + Starts + + + {startsAt.toDateString()} + + + + {startsAt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })} + + + + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', + field: { + rowGap: 6, + }, + grow: { + flex: 1, + }, + inlineRow: { + columnGap: 10, + flexDirection: 'row', + }, + input: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 12, + }, + inputText: { + color: '#111827', }, - buttonText: { - color: '#fff', - fontWeight: '600', + label: { + color: '#6b7280', + fontSize: 13, }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx index a16a27bf..9ee9411f 100644 --- a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx @@ -1,44 +1,65 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' +import PagerView from 'react-native-pager-view' + +const PAGES = [ + { key: 'welcome', title: 'Welcome', body: 'Track your habits in one place.' }, + { key: 'reminders', title: 'Reminders', body: 'Get nudged at the right time.' }, + { key: 'insights', title: 'Insights', body: 'See your streaks grow.' }, +] export default function App() { + const [page, setPage] = useState(0) + return ( - Expo UI PagerView - Replace this scaffold with the requested Expo implementation. - - Start - + setPage(event.nativeEvent.position)} + style={styles.pager} + > + {PAGES.map((item) => ( + + {item.title} + {item.body} + + ))} + + + + {page + 1} / {PAGES.length} + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + body: { + color: '#4b5563', + textAlign: 'center', }, - buttonText: { - color: '#fff', - fontWeight: '600', + indicator: { + color: '#6b7280', + textAlign: 'center', }, - screen: { + page: { alignItems: 'center', + justifyContent: 'center', + padding: 24, + rowGap: 8, + }, + pager: { + flex: 1, + }, + screen: { backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 12, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 22, + fontWeight: '700', }, }) diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx index d7e68775..f17af5b3 100644 --- a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx @@ -1,44 +1,41 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +const COLORS = { + primary: '#2563eb', + onPrimary: '#ffffff', + surface: '#f4f4f5', + onSurface: '#18181b', +} export default function App() { return ( - - Expo UI Material colors - Replace this scaffold with the requested Expo implementation. - - Start - + + Today + + + You have 3 tasks due + + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + banner: { + borderRadius: 12, + padding: 16, }, - buttonText: { - color: '#fff', + bannerText: { + fontSize: 16, fontWeight: '600', }, + heading: { + fontSize: 24, + fontWeight: '700', + }, screen: { - alignItems: 'center', - backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + rowGap: 16, }, }) diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx index 7a78d9db..2b73e06b 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx @@ -1,44 +1,47 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { + const [query, setQuery] = useState('') + return ( - Expo UI native state TextInput - Replace this scaffold with the requested Expo implementation. - - Start - + Search + + + {query ? `Searching for "${query}"` : 'Start typing above'} + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', + input: { + backgroundColor: '#f9fafb', + borderColor: '#e5e7eb', borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 12, }, - buttonText: { - color: '#fff', - fontWeight: '600', + preview: { + color: '#6b7280', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 12, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx index 806a048b..9c03e786 100644 --- a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx @@ -1,44 +1,51 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { Platform, StyleSheet, Text, View } from 'react-native' export default function App() { return ( - Expo UI platform modifiers - Replace this scaffold with the requested Expo implementation. - - Start - + Featured + + Weekly digest + Your top stories, every Monday. + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + card: { + backgroundColor: '#fff', + padding: 16, + rowGap: 6, + }, + cardAndroid: { + borderRadius: 4, + elevation: 4, }, - buttonText: { - color: '#fff', - fontWeight: '600', + cardBody: { + color: '#4b5563', + }, + cardIos: { + borderRadius: 16, + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.15, + shadowRadius: 8, + }, + cardTitle: { + color: '#111827', + fontSize: 18, + fontWeight: '700', }, screen: { - alignItems: 'center', - backgroundColor: '#fff', + backgroundColor: '#f4f4f5', flex: 1, - justifyContent: 'center', padding: 20, - rowGap: 10, - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) From b26a2c2af3758bf8f43b8cb1e451768709d0e543 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 00:52:17 +0400 Subject: [PATCH 14/32] refactor(evals): rebuild Expo references as genuine prompt(app) solutions Make every Expo reference the real result of applying prompt.md to the reseeded starter: each reference now starts from the new starter, applies exactly the prompt's change, satisfies every requirement, and carries no placeholder text or dead imports. - Remove leftover "Replace this scaffold" placeholder reference App.tsx files across all four categories - Rebuild references on top of the realistic starters (migrated-off legacy code, fixed defects, filled stub handlers) - expo-modules/08: reference now writes camera permission to match the prompt (was microphone) - expo-modules/03: reference shows the fixed file/class/Name alignment - expo-modules/07: reference adds correct package.json types/files config - expo-router: add missing index.tsx files; relocate not-found catch-all under docs/ so +not-found takes priority; resolve dead /details links - Restore full reference file sets so each reference mirrors its app/ starter (per repo convention) Co-Authored-By: Claude Opus 4.6 --- .../reference/App.tsx | 44 +++--- .../reference/INLINE_MODULES.md | 7 +- .../src/modules/DeviceAuditModule.kt | 6 + .../reference/App.tsx | 41 +++++ .../modules/WeatherInlineModule.swift | 5 + .../reference/App.tsx | 43 ++++++ .../reference/src/NativeDeviceAudit.ts | 8 +- .../reference/src/index.ts | 3 +- .../reference/App.tsx | 39 +++++ .../reference/ios/AuditLabelView.swift | 20 +++ .../reference/App.tsx | 42 +++++ .../reference/package.json | 19 +++ .../reference/App.tsx | 33 ++++ .../reference/app.config.ts | 16 +- .../reference/plugin/withAuditPermissions.ts | 10 +- .../reference/App.tsx | 41 +++++ .../reference/_layout.tsx | 6 +- .../reference/details.tsx | 18 +++ .../reference/index.tsx | 13 +- .../reference/_layout.tsx | 2 + .../reference/index.tsx | 14 +- .../reference/_layout.tsx | 6 +- .../reference/index.tsx | 17 ++- .../reference/account.tsx | 17 ++- .../reference/index.tsx | 17 +++ .../reference/sign-in.tsx | 17 ++- .../reference/_layout.tsx | 10 +- .../reference/details.tsx | 17 ++- .../reference/index.tsx | 17 ++- .../reference/index.tsx | 16 ++ .../reference/profile.tsx | 4 +- .../reference/server/profile.server.ts | 2 +- .../reference/index.tsx | 9 +- .../reference/+not-found.tsx | 17 ++- .../reference/[...slug].tsx | 2 - .../reference/docs/[...slug].tsx | 12 ++ .../reference/index.tsx | 16 ++ .../reference/App.tsx | 88 ++++++++--- .../reference/App.tsx | 97 +++++++++--- .../reference/App.tsx | 143 +++++++++++++----- .../reference/App.tsx | 66 ++++---- .../reference/App.tsx | 94 ++++++++---- .../reference/App.tsx | 97 ++++++++---- .../reference/App.tsx | 92 ++++++++--- .../reference/App.tsx | 113 +++++++++----- .../reference/App.tsx | 82 ++++++---- .../reference/App.tsx | 125 ++++++++++----- .../reference/App.tsx | 34 +++-- .../reference/App.tsx | 86 ++++++----- .../reference/App.tsx | 54 +++---- .../reference/App.tsx | 99 ++++++++---- .../reference/App.tsx | 71 ++++++--- .../reference/App.tsx | 101 ++++++++----- .../reference/App.tsx | 140 +++++++++++++---- .../reference/App.tsx | 140 ++++++++++++----- .../reference/App.tsx | 78 +++++++--- .../reference/App.tsx | 97 +++++++++--- .../reference/App.tsx | 47 +++--- .../reference/App.tsx | 104 ++++++++----- .../reference/App.tsx | 103 ++++++++----- .../reference/App.tsx | 109 ++++++++----- .../reference/App.tsx | 26 +--- .../reference/app.config.ts | 2 - .../reference/App.tsx | 55 ++----- .../reference/App.tsx | 65 ++------ .../reference/App.tsx | 62 ++++---- .../reference/App.tsx | 74 +++++---- .../reference/App.tsx | 97 ++++++++---- .../reference/App.tsx | 69 +++++---- .../reference/App.tsx | 56 ++----- .../reference/App.tsx | 71 +++------ .../reference/App.tsx | 93 ++++++------ 72 files changed, 2409 insertions(+), 1147 deletions(-) create mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx create mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx create mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx create mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json create mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx create mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx create mode 100644 evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx create mode 100644 evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/index.tsx create mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx delete mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx create mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx index 1c024aec..eca68eb4 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx @@ -1,28 +1,33 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { requireNativeModule } from 'expo' +import { StyleSheet, Text, View } from 'react-native' + +type DeviceAuditModule = { + source: string + getOsVersion(): string +} + +let osVersion = 'unknown' +let source = 'unavailable' + +try { + const DeviceAudit = requireNativeModule('DeviceAuditModule') + osVersion = DeviceAudit.getOsVersion() + source = DeviceAudit.source +} catch { + // Native module is not registered with the current build yet. +} export default function App() { return ( - Inline module config - Replace this scaffold with the requested Expo implementation. - - Start - + Device Audit + OS version: {osVersion} + Module source: {source} ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', @@ -31,14 +36,13 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 10, }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, title: { color: '#111827', fontSize: 20, fontWeight: '600', textAlign: 'center', }, + row: { + color: '#374151', + }, }) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md index 1d318895..e3549c43 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md @@ -1,3 +1,8 @@ # Inline Modules -Changing `expo.experiments.inlineModules` or its `watchedDirectories` requires regenerating the native project with `npx expo prebuild` or rebuilding the development client so the generated module providers include the inline module. +Native modules under `src/` are written with the Expo Modules Kotlin/Swift DSL so +they can be picked up as inline modules without publishing a separate package. + +Changes to the inline module configuration require regenerating the native project +(`npx expo prebuild`) or rebuilding the development client so the generated module +providers include the inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt index 5195a634..808e1bf1 100644 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt +++ b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt @@ -1,11 +1,17 @@ package expo.modules.deviceaudit +import android.os.Build import expo.modules.kotlin.modules.Module import expo.modules.kotlin.modules.ModuleDefinition class DeviceAuditModule : Module() { override fun definition() = ModuleDefinition { Name("DeviceAuditModule") + Constant("source") { "inline" } + + Function("getOsVersion") { + Build.VERSION.RELEASE + } } } diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx new file mode 100644 index 00000000..4360f08c --- /dev/null +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx @@ -0,0 +1,41 @@ +import { StyleSheet, Text, View } from 'react-native' + +import { WeatherInlineModule } from './index' + +let unit = 'unavailable' + +try { + unit = WeatherInlineModule.unit() +} catch { + // The native module did not load under the requested name. +} + +export default function App() { + return ( + + Weather + Temperature unit: {unit} + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift index 97f88e75..d07dabf2 100644 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift +++ b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift @@ -3,8 +3,13 @@ import ExpoModulesCore public class WeatherInlineModule: Module { public func definition() -> ModuleDefinition { Name("WeatherInlineModule") + Function("unit") { return "celsius" } + + Function("currentTemperature") { + return 21 + } } } diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx new file mode 100644 index 00000000..d6daad5b --- /dev/null +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx @@ -0,0 +1,43 @@ +import { useEffect, useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' + +import { DeviceAudit } from './src' + +export default function App() { + const [battery, setBattery] = useState('loading…') + + useEffect(() => { + // No types here, so this call site is unchecked. + DeviceAudit.getBatteryLabelAsync() + .then((label: string) => setBattery(label)) + .catch(() => setBattery('unavailable')) + }, []) + + return ( + + Device Audit + Battery: {battery} + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts index 3741dbba..8dbfcf42 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts @@ -1,11 +1,7 @@ import { requireNativeModule } from 'expo-modules-core' -type DeviceAuditModule = { +export type DeviceAuditModule = { getBatteryLabelAsync(): Promise } -const NativeDeviceAudit = requireNativeModule('DeviceAudit') - -export async function getBatteryLabel() { - return NativeDeviceAudit.getBatteryLabelAsync() -} +export const DeviceAudit = requireNativeModule('DeviceAudit') diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts index 8082f40b..a2e9004d 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts @@ -1 +1,2 @@ -export { getBatteryLabel } from './NativeDeviceAudit' +export { DeviceAudit } from './NativeDeviceAudit' +export type { DeviceAuditModule } from './NativeDeviceAudit' diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx new file mode 100644 index 00000000..6798f6b7 --- /dev/null +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx @@ -0,0 +1,39 @@ +import { StyleSheet, Text, View } from 'react-native' + +import AuditLabel from './src/AuditLabel' + +export default function App() { + return ( + + Audit Label + { + console.log('AuditLabel is ready') + }} + style={styles.label} + /> + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + label: { + height: 44, + width: 200, + }, +}) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift index 6b252402..d693c8df 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift @@ -2,4 +2,24 @@ import ExpoModulesCore final class AuditLabelView: ExpoView { let label = UILabel() + let onReady = EventDispatcher() + + required init(appContext: AppContext? = nil) { + super.init(appContext: appContext) + label.numberOfLines = 0 + addSubview(label) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + addGestureRecognizer(tapGesture) + } + + override func layoutSubviews() { + super.layoutSubviews() + label.frame = bounds + } + + @objc + private func handleTap() { + onReady() + } } diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx new file mode 100644 index 00000000..b6f514f3 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx @@ -0,0 +1,42 @@ +import { useEffect, useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' + +import { audit, type AuditResult } from './src' + +export default function App() { + const [result, setResult] = useState(null) + + useEffect(() => { + audit().then(setResult) + }, []) + + return ( + + Audit + + Status: {result ? (result.ok ? 'ok' : 'failed') : 'running…'} + + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json new file mode 100644 index 00000000..871fe040 --- /dev/null +++ b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json @@ -0,0 +1,19 @@ +{ + "name": "expo-audit", + "version": "1.0.0", + "main": "build/index.js", + "types": "build/index.d.ts", + "files": [ + "src", + "build", + "expo-module.config.json" + ], + "scripts": { + "build": "expo-module build", + "typegen": "tsc --emitDeclarationOnly --outDir build" + }, + "devDependencies": { + "expo-module-scripts": "^4.0.0", + "typescript": "^5.3.0" + } +} diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx new file mode 100644 index 00000000..27b0b48d --- /dev/null +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx @@ -0,0 +1,33 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function App() { + return ( + + Audit + + Camera access is required to run a device audit. + + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, +}) diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts index cd173231..b5b5a9da 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts @@ -1,7 +1,11 @@ -export default { - expo: { - plugins: [ - ['./plugin/withAuditPermissions', { microphoneMessage: 'Allow audio audit recording.' }], - ], - }, +import { ExpoConfig } from 'expo/config' + +const config: ExpoConfig = { + name: 'audit', + slug: 'audit', + plugins: [ + ['./plugin/withAuditPermissions', { cameraMessage: 'Allow camera access to run a device audit.' }], + ], } + +export default config diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts index d48ed832..d45e552f 100644 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts +++ b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts @@ -1,14 +1,14 @@ -import { AndroidConfig, ConfigPlugin, IOSConfig, withAndroidManifest, withInfoPlist } from 'expo/config-plugins' +import { AndroidConfig, ConfigPlugin, withAndroidManifest, withInfoPlist } from 'expo/config-plugins' -const MICROPHONE = 'android.permission.RECORD_AUDIO' +const CAMERA = 'android.permission.CAMERA' -export const withAuditPermissions: ConfigPlugin<{ microphoneMessage: string }> = (config, props) => { +export const withAuditPermissions: ConfigPlugin<{ cameraMessage: string }> = (config, props) => { config = withInfoPlist(config, (nextConfig) => { - nextConfig.modResults.NSMicrophoneUsageDescription = props.microphoneMessage + nextConfig.modResults.NSCameraUsageDescription = props.cameraMessage return nextConfig }) return withAndroidManifest(config, (nextConfig) => { - AndroidConfig.Permissions.addPermission(nextConfig.modResults, MICROPHONE) + AndroidConfig.Permissions.addPermission(nextConfig.modResults, CAMERA) return nextConfig }) } diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx new file mode 100644 index 00000000..fe6a0653 --- /dev/null +++ b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx @@ -0,0 +1,41 @@ +import { StyleSheet, Text, View } from 'react-native' + +import { getPlatform } from './src' + +let platform = 'unknown' + +try { + platform = getPlatform() +} catch { + // No implementation is registered for the current platform. +} + +export default function App() { + return ( + + Audit + Running on: {platform} + + ) +} + +const styles = StyleSheet.create({ + screen: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 10, + }, + title: { + color: '#111827', + fontSize: 20, + fontWeight: '600', + textAlign: 'center', + }, + subtitle: { + color: '#6b7280', + textAlign: 'center', + }, +}) diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx index 81c9df68..51570c06 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx @@ -2,5 +2,9 @@ import { Stack, useNavigation } from 'expo-router' export default function Layout() { useNavigation() - return + return ( + + + + ) } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx new file mode 100644 index 00000000..c4273ee8 --- /dev/null +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/details.tsx @@ -0,0 +1,18 @@ +import { useLocalSearchParams } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' + +export default function Details() { + const { id } = useLocalSearchParams<{ id?: string }>() + + return ( + + Details + Product {id ?? 'unknown'} + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx index 307c5221..194b87ed 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx @@ -1,11 +1,16 @@ import { Link } from 'expo-router' -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home - Details + + Products + View details ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx index 70fa084f..aa15f844 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx @@ -7,6 +7,8 @@ export default function Layout() { ( Alert.alert('New item')}> + diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx index 307c5221..a5bf2cf3 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx @@ -1,11 +1,15 @@ -import { Link } from 'expo-router' -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function Index() { return ( - - Home - Details + + Inbox + Tap the header action to add a new item. ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx index ae441594..a14c4536 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx @@ -1,5 +1,9 @@ import { Stack } from 'expo-router' export default function Layout() { - return + return ( + + + + ) } diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx index 598d2a13..37ae7b1c 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/index.tsx @@ -1,9 +1,20 @@ -import { ScrollView, Text } from 'react-native' +import { ScrollView, StyleSheet, Text } from 'react-native' + +const ITEMS = Array.from({ length: 20 }, (_, i) => `Activity ${i + 1}`) export default function Index() { return ( - - Large-title content starts inside the scroll view. + + {ITEMS.map((item) => ( + + {item} + + ))} ) } + +const styles = StyleSheet.create({ + container: { padding: 16, gap: 8 }, + row: { fontSize: 16 }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx index 6f710168..5090e3ba 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/account.tsx @@ -1,2 +1,15 @@ -import { Text } from 'react-native' -export default function Account() { return Account } +import { StyleSheet, Text, View } from 'react-native' + +export default function Account() { + return ( + + Account + Signed-in profile details. + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/index.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/index.tsx new file mode 100644 index 00000000..96a6b777 --- /dev/null +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/index.tsx @@ -0,0 +1,17 @@ +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' + +export default function Index() { + return ( + + Welcome + Account + Sign in + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx index 4e347807..d85c982d 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/sign-in.tsx @@ -1,2 +1,15 @@ -import { Text } from 'react-native' -export default function SignIn() { return Sign in } +import { StyleSheet, Text, View } from 'react-native' + +export default function SignIn() { + return ( + + Sign in + Authenticate to access your account. + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx index 61625f48..57ccc1dd 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/_layout.tsx @@ -1,2 +1,10 @@ import { Stack } from 'expo-router' -export default function Layout() { return } + +export default function Layout() { + return ( + + + + + ) +} diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx index 84e5e26d..47f046e8 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/details.tsx @@ -1,7 +1,20 @@ import { useLocalSearchParams } from 'expo-router' -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function Details() { const { id, tab } = useLocalSearchParams<{ id?: string; tab?: string }>() - return {String(id ?? 'missing')} - {String(tab ?? 'overview')} + + return ( + + Details + + Product {id ?? 'unknown'} — {tab ?? 'overview'} + + + ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx index 307c5221..57102183 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/reference/index.tsx @@ -1,11 +1,20 @@ import { Link } from 'expo-router' -import { Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' + +const PRODUCT = { id: '42', tab: 'overview' } export default function Index() { return ( - - Home - Details + + Products + + Open details + ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx new file mode 100644 index 00000000..b341b6ea --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx @@ -0,0 +1,16 @@ +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + View profile + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx index d2313dba..536f1be1 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx @@ -1,9 +1,9 @@ import { useLoaderData } from 'expo-router' import { Text } from 'react-native' -import { readProfile } from './server/profile.server' +import { getProfile } from './server/profile.server' export async function loader() { - return readProfile() + return getProfile() } export default function Profile() { diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts index 8e74015f..5a6cd4e6 100644 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts +++ b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts @@ -1,3 +1,3 @@ -export async function readProfile() { +export async function getProfile() { return { name: process.env.PROFILE_NAME ?? 'Expo' } } diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx index b76776db..3287f765 100644 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx +++ b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx @@ -1,13 +1,20 @@ +import { use } from 'react' import { Text, View } from 'react-native' +const contentPromise = new Promise((resolve) => + setTimeout(() => resolve('Async route content'), 500), +) + export function SuspenseFallback() { return Loading route... } export default function Index() { + const content = use(contentPromise) + return ( - Async route content + {content} ) } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx index 344f8417..a4ee8372 100644 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx @@ -1,6 +1,17 @@ -import { Link, Unmatched } from 'expo-router' -import { Text, View } from 'react-native' +import { Link, Stack } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' export default function NotFound() { - return Missing routeGo home + return ( + + + This screen does not exist. + Go to home screen + + ) } + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx deleted file mode 100644 index a976440e..00000000 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/[...slug].tsx +++ /dev/null @@ -1,2 +0,0 @@ -import { Text } from 'react-native' -export default function CatchAll() { return Known catch-all content } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx new file mode 100644 index 00000000..ca75305d --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx @@ -0,0 +1,12 @@ +import { useLocalSearchParams } from 'expo-router' +import { Text, View } from 'react-native' + +export default function Docs() { + const { slug } = useLocalSearchParams<{ slug?: string[] }>() + + return ( + + Docs: {slug?.join('/') ?? 'index'} + + ) +} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx new file mode 100644 index 00000000..b6da9453 --- /dev/null +++ b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx @@ -0,0 +1,16 @@ +import { Link } from 'expo-router' +import { StyleSheet, Text, View } from 'react-native' + +export default function Index() { + return ( + + Home + Docs + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx index 7f7c718d..9fa05491 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/reference/App.tsx @@ -1,13 +1,11 @@ import { CameraView, useCameraPermissions } from 'expo-camera' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { AppState, Linking, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { const [permission, requestPermission, getPermission] = useCameraPermissions() const [requesting, setRequesting] = useState(false) - const state = requesting ? 'requesting' : permission?.granted ? 'granted' : permission?.canAskAgain === false ? 'blocked' : 'denied' - useEffect(() => { const sub = AppState.addEventListener('change', (nextState) => { if (nextState === 'active') void getPermission() @@ -15,8 +13,10 @@ export default function App() { return () => sub.remove() }, [getPermission]) - const request = async () => { - if (requesting || state === 'blocked') return + const blocked = permission?.granted === false && permission.canAskAgain === false + + const handleRequestPermission = async () => { + if (requesting || blocked) return setRequesting(true) try { await requestPermission() @@ -25,54 +25,92 @@ export default function App() { } } + const handleOpenSettings = () => { + void Linking.openSettings() + } + return ( - Camera access - {permission?.granted ? : Preview unavailable until camera permission is granted.} - Request or retry - {state === 'blocked' ? Linking.openSettings()} style={styles.action}>Open settings : null} + Camera + + + {permission?.granted ? ( + + ) : ( + Camera is off + )} + + + {blocked ? ( + + + Camera access is turned off. Enable it in Settings to continue. + + + Open Settings + + + ) : ( + + + {permission?.granted ? 'Camera Enabled' : 'Enable Camera'} + + + )} ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, + camera: { + height: '100%', width: '100%', }, - media: { - backgroundColor: '#e5e7eb', + preview: { + alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', borderRadius: 12, - height: 180, + justifyContent: 'center', overflow: 'hidden', width: '100%', }, + previewText: { + color: '#9ca3af', + }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, + rowGap: 16, + }, + statusBlock: { + alignItems: 'center', + rowGap: 10, }, - subtitle: { - color: '#4b5563', + statusText: { + color: '#6b7280', + textAlign: 'center', }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx index ef6d93ce..1207a065 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx @@ -1,67 +1,114 @@ import { CameraView, useCameraPermissions } from 'expo-camera' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useRef, useState } from 'react' +import { AppState, Pressable, StyleSheet, Switch, Text, View } from 'react-native' export default function App() { const [permission, requestPermission] = useCameraPermissions() + const [cameraEnabled, setCameraEnabled] = useState(true) const [appActive, setAppActive] = useState(AppState.currentState === 'active') - const [previewEnabled, setPreviewEnabled] = useState(true) + const cameraRef = useRef(null) useEffect(() => { - const sub = AppState.addEventListener('change', (state) => setAppActive(state === 'active')) + const sub = AppState.addEventListener('change', (state) => + setAppActive(state === 'active'), + ) return () => sub.remove() }, []) - const cameraActive = Boolean(permission?.granted && appActive && previewEnabled) + const cameraActive = Boolean(permission?.granted) && appActive && cameraEnabled + + const handleTakePhoto = async () => { + if (!permission?.granted) { + await requestPermission() + return + } + await cameraRef.current?.takePictureAsync() + } return ( - Lifecycle camera - {permission?.granted ? : Camera is not mounted until permission is granted.} - requestPermission()} style={styles.action}>Grant camera - setPreviewEnabled((value) => !value)} style={styles.action}>{previewEnabled ? 'Pause preview' : 'Resume preview'} + Camera Preview + + + {permission?.granted ? ( + cameraActive ? ( + + ) : ( + Camera paused + ) + ) : ( + Camera access required + )} + + + + Camera enabled + + + + + + {permission?.granted ? 'Take Photo' : 'Enable Camera'} + + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonDisabled: { + backgroundColor: '#9ca3af', + }, + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, + camera: { + height: '100%', width: '100%', }, - media: { - backgroundColor: '#e5e7eb', + preview: { + alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', borderRadius: 12, - height: 180, + justifyContent: 'center', overflow: 'hidden', width: '100%', }, + previewText: { + color: '#9ca3af', + }, + row: { + alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx index 5595a269..543e4fcc 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx @@ -1,80 +1,143 @@ import { CameraView, useCameraPermissions, useMicrophonePermissions } from 'expo-camera' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useRef, useState } from 'react' +import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' export default function App() { const [cameraPermission, requestCamera] = useCameraPermissions() const [micPermission, requestMic] = useMicrophonePermissions() - const [lastScan, setLastScan] = useState('') - const [audioEnabled, setAudioEnabled] = useState(false) - const lastScanRef = useRef('') + const [recordAudio, setRecordAudio] = useState(false) + const [lastScan, setLastScan] = useState(null) + const lastScanRef = useRef(null) + const cameraRef = useRef(null) - const enableAudio = async () => { - const result = await requestMic() - setAudioEnabled(result.granted) + const handleToggleAudio = async (value: boolean) => { + if (!value) { + setRecordAudio(false) + return + } + const result = micPermission?.granted ? micPermission : await requestMic() + setRecordAudio(result.granted) + } + + const handleStartRecording = async () => { + if (!cameraPermission?.granted) { + await requestCamera() + return + } + await cameraRef.current?.recordAsync() } return ( Scanner - {cameraPermission?.granted ? ( - { - if (event.data === lastScanRef.current) return - lastScanRef.current = event.data - setLastScan(event.data) - }} - style={styles.media} - /> - ) : Grant camera permission to scan.} - Last scan: {lastScan || 'none'} - requestCamera()} style={styles.action}>Grant camera - {micPermission?.granted ? 'Audio ready' : 'Enable audio'} + + + {cameraPermission?.granted ? ( + { + if (event.data === lastScanRef.current) return + lastScanRef.current = event.data + setLastScan(event.data) + }} + style={styles.camera} + /> + ) : ( + <> + + Point at a barcode + + )} + + + + Last scan + {lastScan ?? '—'} + + + + Record audio + + + + + + {cameraPermission?.granted ? 'Record Video' : 'Enable Camera'} + + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, + camera: { + height: '100%', width: '100%', }, - media: { - backgroundColor: '#e5e7eb', + preview: { + alignItems: 'center', + aspectRatio: 3 / 4, + backgroundColor: '#1f2937', borderRadius: 12, - height: 180, + justifyContent: 'center', overflow: 'hidden', + rowGap: 12, width: '100%', }, + previewText: { + color: '#9ca3af', + }, + resultLabel: { + color: '#6b7280', + }, + resultRow: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + resultValue: { + color: '#111827', + fontWeight: '600', + }, + row: { + alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, + scanFrame: { + borderColor: '#22c55e', + borderRadius: 8, + borderWidth: 2, + height: 120, + width: 180, + }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx index 4d54838b..51613bf4 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx @@ -1,73 +1,83 @@ import * as ImagePicker from 'expo-image-picker' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const [assetUri, setAssetUri] = useState(null) - const [message, setMessage] = useState('No image selected.') + const [imageUri, setImageUri] = useState(null) + const [status, setStatus] = useState('No image selected') - const pick = async () => { + const handlePickImage = async () => { const result = await ImagePicker.launchImageLibraryAsync({ allowsEditing: true, mediaTypes: ['images'], quality: 0.8, }) if (result.canceled || !result.assets?.length) { - setAssetUri(null) - setMessage('Selection canceled.') + setImageUri(null) + setStatus('No image selected') return } - setAssetUri(result.assets[0].uri) - setMessage(result.assets[0].fileName ?? 'Image selected.') + setImageUri(result.assets[0].uri) + setStatus('Image selected') } return ( - Image picker - {assetUri ? : {message}} - Choose image + Profile Photo + + + {imageUri ? ( + + ) : ( + {status} + )} + + + + Choose from Library + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, + image: { + height: '100%', width: '100%', }, - media: { - backgroundColor: '#e5e7eb', + preview: { + alignItems: 'center', + aspectRatio: 1, + backgroundColor: '#f3f4f6', borderRadius: 12, - height: 180, + justifyContent: 'center', overflow: 'hidden', width: '100%', }, + previewText: { + color: '#9ca3af', + }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx index 5925b540..f9962cb2 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx @@ -1,72 +1,104 @@ import * as ImagePicker from 'expo-image-picker' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const [status, setStatus] = useState('Permission not requested.') const [videoUri, setVideoUri] = useState(null) + const [status, setStatus] = useState('No video selected') - const pickVideo = async () => { + const handlePickVideo = async () => { const existing = await ImagePicker.getMediaLibraryPermissionsAsync() - const permission = existing.granted ? existing : await ImagePicker.requestMediaLibraryPermissionsAsync(false) + const permission = existing.granted + ? existing + : await ImagePicker.requestMediaLibraryPermissionsAsync(false) if (!permission.granted) { - setStatus(permission.canAskAgain ? 'Video access denied.' : 'Open settings to enable video access.') + setStatus( + permission.canAskAgain + ? 'Video access denied' + : 'Enable video access in Settings', + ) return } - const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['videos'], videoMaxDuration: 60 }) - const asset = !result.canceled && result.assets?.[0]?.type === 'video' ? result.assets[0] : null - setVideoUri(asset?.uri ?? null) - setStatus(asset ? `Selected ${Math.round((asset.duration ?? 0) / 1000)}s video.` : 'No video selected.') + if (permission.accessPrivileges === 'limited') { + setStatus('Limited library access — only selected videos are available') + } + const result = await ImagePicker.launchImageLibraryAsync({ + mediaTypes: ['videos'], + videoMaxDuration: 60, + }) + const asset = + !result.canceled && result.assets?.[0]?.type === 'video' + ? result.assets[0] + : null + if (!asset) { + setVideoUri(null) + setStatus('No video selected') + return + } + setVideoUri(asset.uri) + setStatus(`Selected ${Math.round((asset.duration ?? 0) / 1000)}s video`) } return ( - Video picker - {status} - {videoUri ?? 'No video uri'} - Choose video + Upload Video + + + {videoUri ? ( + + {videoUri} + + ) : ( + {status} + )} + + + {videoUri ? {status} : null} + + + Choose Video + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', + preview: { + alignItems: 'center', + aspectRatio: 16 / 9, + backgroundColor: '#111827', borderRadius: 12, - borderWidth: 1, - padding: 14, + justifyContent: 'center', + paddingHorizontal: 12, width: '100%', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + previewText: { + color: '#9ca3af', }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, + rowGap: 16, }, - subtitle: { - color: '#4b5563', + status: { + color: '#6b7280', }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx index 01d4ff81..56efff6b 100644 --- a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/reference/App.tsx @@ -1,68 +1,105 @@ import * as Location from 'expo-location' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +type Coordinates = { + latitude: number + longitude: number +} export default function App() { - const [summary, setSummary] = useState('Location not loaded.') + const [coords, setCoords] = useState(null) + const [address, setAddress] = useState(null) - const locate = async () => { - const permission = await Location.requestForegroundPermissionsAsync() + const handleFindLocation = async () => { + let permission = await Location.getForegroundPermissionsAsync() + if (!permission.granted) { + permission = await Location.requestForegroundPermissionsAsync() + } if (!permission.granted) { - setSummary('Foreground location permission denied.') + setCoords(null) + setAddress('Location permission denied') + return + } + + const position = await Location.getCurrentPositionAsync({ + accuracy: Location.Accuracy.Balanced, + }) + setCoords(position.coords) + + const places = await Location.reverseGeocodeAsync(position.coords) + if (!places.length) { + setAddress('Address unavailable') return } - const position = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced }) - const [place] = await Location.reverseGeocodeAsync(position.coords) - setSummary(place ? [place.city, place.region, place.country].filter(Boolean).join(', ') : 'Coordinates found, address unavailable.') + const place = places[0] + setAddress( + [place.city, place.region, place.country].filter(Boolean).join(', ') || + 'Address unavailable', + ) } return ( - Location lookup - {summary} - Use current location + Where am I? + + + Coordinates + + {coords + ? `${coords.latitude.toFixed(5)}, ${coords.longitude.toFixed(5)}` + : 'Unknown'} + + + Address + {address ?? 'Unknown'} + + + + Find My Location + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', + backgroundColor: '#f3f4f6', borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + padding: 16, + rowGap: 6, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 16, + fontWeight: '600', + marginBottom: 6, }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx index b5810774..074ac610 100644 --- a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/reference/App.tsx @@ -1,9 +1,9 @@ import * as Location from 'expo-location' import * as TaskManager from 'expo-task-manager' import { useState } from 'react' -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Switch, Text, View } from 'react-native' -const TASK_NAME = 'background-location-audit' +const TASK_NAME = 'trip-tracking-location' TaskManager.defineTask(TASK_NAME, async ({ data, error }) => { if (error) return @@ -11,20 +11,32 @@ TaskManager.defineTask(TASK_NAME, async ({ data, error }) => { }) export default function App() { - const [status, setStatus] = useState('Background tracking is off.') + const [tracking, setTracking] = useState(false) + const [lastUpdate, setLastUpdate] = useState(null) + + const handleToggleTracking = async (value: boolean) => { + if (!value) { + if (await Location.hasStartedLocationUpdatesAsync(TASK_NAME)) { + await Location.stopLocationUpdatesAsync(TASK_NAME) + } + setTracking(false) + setLastUpdate('Tracking stopped') + return + } - const start = async () => { const foreground = await Location.requestForegroundPermissionsAsync() if (!foreground.granted) { - setStatus('Foreground permission is required first.') + setLastUpdate('Foreground permission required') return } const background = await Location.requestBackgroundPermissionsAsync() if (!background.granted) { - setStatus('Background permission denied.') + setLastUpdate('Background permission denied') return } - const alreadyStarted = await Location.hasStartedLocationUpdatesAsync(TASK_NAME) + + const alreadyStarted = + await Location.hasStartedLocationUpdatesAsync(TASK_NAME) if (!alreadyStarted) { await Location.startLocationUpdatesAsync(TASK_NAME, { accuracy: Location.Accuracy.Balanced, @@ -32,30 +44,62 @@ export default function App() { pausesUpdatesAutomatically: true, }) } - setStatus('Background tracking is active.') - } - - const stop = async () => { - if (await Location.hasStartedLocationUpdatesAsync(TASK_NAME)) { - await Location.stopLocationUpdatesAsync(TASK_NAME) - } - setStatus('Background tracking is off.') + setTracking(true) + setLastUpdate('Tracking started') } return ( - Background location - {status} - Enable - Disable + Trip Tracking + + + Last update + {lastUpdate ?? 'No updates yet'} + + + + Track in background + + ) } const styles = StyleSheet.create({ - action: { backgroundColor: '#111827', borderRadius: 10, padding: 12 }, - actionText: { color: '#fff', fontWeight: '600' }, - screen: { backgroundColor: '#fff', flex: 1, padding: 20, rowGap: 12 }, - subtitle: { color: '#4b5563' }, - title: { color: '#111827', fontSize: 20, fontWeight: '700' }, + card: { + backgroundColor: '#f3f4f6', + borderRadius: 12, + padding: 16, + rowGap: 6, + }, + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 16, + fontWeight: '600', + }, + row: { + alignItems: 'center', + flexDirection: 'row', + justifyContent: 'space-between', + }, + rowLabel: { + color: '#111827', + fontSize: 16, + }, + screen: { + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 16, + }, + title: { + color: '#111827', + fontSize: 24, + fontWeight: '700', + }, }) diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx index 5b343a96..04945e09 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx @@ -1,71 +1,114 @@ import * as Location from 'expo-location' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Linking, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const [permission, setPermission] = useState(null) - const [message, setMessage] = useState('Check location accuracy.') + const [permission, setPermission] = + useState(null) - const refresh = async () => { - const nextPermission = await Location.requestForegroundPermissionsAsync() - setPermission(nextPermission) - if (!nextPermission.granted) { - setMessage('Location permission denied.') - return - } - const accuracy = nextPermission.android?.accuracy ?? nextPermission.ios?.scope ?? 'unknown' - const position = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy.Balanced }) - setMessage(`Accuracy: ${accuracy}; lat ${position.coords.latitude.toFixed(3)}`) + const handleRefresh = async () => { + const next = await Location.requestForegroundPermissionsAsync() + setPermission(next) + if (!next.granted) return + // Touch the position API with explicit accuracy options; do not assume the + // grant implies precise location. + await Location.getCurrentPositionAsync({ + accuracy: Location.Accuracy.Balanced, + }) } + const permissionStatus = permission?.status ?? 'undetermined' + // iOS exposes an authorization scope; Android exposes fine/coarse accuracy. + // A granted permission can still be approximate, so do not assume precise. + const androidAccuracy = permission?.android?.accuracy + const iosScope = permission?.ios?.scope + const preciseAccuracy = androidAccuracy === 'fine' + const accuracyDetail = + androidAccuracy ?? (iosScope ? `iOS ${iosScope}` : undefined) + const blocked = permission != null && !permission.granted && !permission.canAskAgain + return ( - Accuracy status - {message} - Refresh - {permission?.canAskAgain === false ? Linking.openSettings()} style={styles.action}>Open settings : null} + Location Status + + + + Permission + {permissionStatus} + + + Accuracy + + {preciseAccuracy ? 'Precise' : 'Approximate'} + + + {!preciseAccuracy && permission?.granted ? ( + + Only approximate location is available + {accuracyDetail ? ` (${accuracyDetail})` : ''}. + + ) : null} + + + + Refresh Status + + + {blocked ? ( + Linking.openSettings()}> + Open Settings + + ) : null} ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', + backgroundColor: '#f3f4f6', borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + padding: 16, + rowGap: 12, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + note: { + color: '#6b7280', + fontSize: 13, }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, + rowGap: 16, + }, + statusLabel: { + color: '#6b7280', + fontSize: 15, + }, + statusRow: { + flexDirection: 'row', + justifyContent: 'space-between', }, - subtitle: { - color: '#4b5563', + statusValue: { + color: '#111827', + fontSize: 15, + fontWeight: '600', + textTransform: 'capitalize', }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx index 13419d92..d639b755 100644 --- a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/reference/App.tsx @@ -1,12 +1,14 @@ import Constants from 'expo-constants' import * as Notifications from 'expo-notifications' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Platform, Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const [status, setStatus] = useState('Not registered.') + const [pushToken, setPushToken] = useState(null) + const [error, setError] = useState(null) - const register = async () => { + const handleRegister = async () => { + setError(null) try { if (Platform.OS === 'android') { await Notifications.setNotificationChannelAsync('default', { @@ -14,70 +16,86 @@ export default function App() { name: 'Default', }) } - const permission = await Notifications.requestPermissionsAsync() + + const existing = await Notifications.getPermissionsAsync() + const permission = existing.granted + ? existing + : await Notifications.requestPermissionsAsync() if (!permission.granted) { - setStatus('Notification permission denied.') + setError('Notification permission denied') return } - const projectId = Constants.easConfig?.projectId ?? Constants.expoConfig?.extra?.eas?.projectId + + const projectId = + Constants.easConfig?.projectId ?? + Constants.expoConfig?.extra?.eas?.projectId if (!projectId) { - setStatus('Missing EAS project id.') + setError('Missing EAS project id') return } + const token = await Notifications.getExpoPushTokenAsync({ projectId }) - setStatus(token.data) - } catch (error) { - setStatus(error instanceof Error ? error.message : 'Token registration failed.') + setPushToken(token.data) + } catch (err) { + setError(err instanceof Error ? err.message : 'Token registration failed') } } return ( - Push token - {status} - Register + Push Notifications + + + Expo push token + + {error ?? pushToken ?? 'Not registered'} + + + + + Register for Notifications + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', + backgroundColor: '#f3f4f6', borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + padding: 16, + rowGap: 6, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + cardLabel: { + color: '#6b7280', + fontSize: 13, + }, + cardValue: { + color: '#111827', + fontSize: 14, + fontWeight: '600', }, screen: { backgroundColor: '#fff', flex: 1, + justifyContent: 'center', padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx index dc10bd9a..448cfc71 100644 --- a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/reference/App.tsx @@ -1,69 +1,116 @@ import * as Notifications from 'expo-notifications' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { FlatList, StyleSheet, Text, View } from 'react-native' + +type InboxItem = { + id: string + title: string + body: string + tapped: boolean +} export default function App() { - const [events, setEvents] = useState([]) + const [items, setItems] = useState([]) useEffect(() => { - const received = Notifications.addNotificationReceivedListener((notification) => { - setEvents((items) => [notification.request.identifier, ...items]) - }) - const responses = Notifications.addNotificationResponseReceivedListener((response) => { - setEvents((items) => [`tap:${response.notification.request.identifier}`, ...items]) - }) + const receivedSub = Notifications.addNotificationReceivedListener( + (notification) => { + const { identifier, content } = notification.request + setItems((prev) => [ + { + id: identifier, + title: content.title ?? 'Notification', + body: content.body ?? '', + tapped: false, + }, + ...prev, + ]) + }, + ) + + const responseSub = Notifications.addNotificationResponseReceivedListener( + (response) => { + const { identifier, content } = response.notification.request + setItems((prev) => { + const exists = prev.some((item) => item.id === identifier) + if (exists) { + return prev.map((item) => + item.id === identifier ? { ...item, tapped: true } : item, + ) + } + return [ + { + id: identifier, + title: content.title ?? 'Notification', + body: content.body ?? '', + tapped: true, + }, + ...prev, + ] + }) + }, + ) + return () => { - received.remove() - responses.remove() + receivedSub.remove() + responseSub.remove() } }, []) return ( - Notification inbox - {events.map((event) => {event})} + Inbox + + item.id} + ListEmptyComponent={ + No notifications yet. + } + renderItem={({ item }) => ( + + {item.title} + {item.body} + + )} + /> ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', + empty: { + color: '#9ca3af', + marginTop: 24, + textAlign: 'center', + }, + row: { + backgroundColor: '#f3f4f6', borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + marginBottom: 8, + padding: 12, + rowGap: 4, }, - actionText: { - color: '#fff', - fontWeight: '600', + rowBody: { + color: '#6b7280', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + rowTapped: { + opacity: 0.6, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + rowTitle: { + color: '#111827', + fontWeight: '600', }, screen: { backgroundColor: '#fff', flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + paddingHorizontal: 20, + paddingTop: 64, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', + marginBottom: 16, }, }) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx index ad6425f5..87e1f802 100644 --- a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx @@ -1,12 +1,28 @@ +import * as Notifications from 'expo-notifications' import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { + const handleSendTest = async () => { + const permission = await Notifications.getPermissionsAsync() + if (!permission.granted) { + const requested = await Notifications.requestPermissionsAsync() + if (!requested.granted) return + } + await Notifications.scheduleNotificationAsync({ + content: { title: 'Test notification', body: 'Configured via app.config.ts.' }, + trigger: null, + }) + } + return ( - Notifications config - Replace this scaffold with the requested Expo implementation. - - Start + Notifications + + Notification appearance is configured at the native level. + + + + Send Test Notification ) @@ -22,23 +38,21 @@ const styles = StyleSheet.create({ buttonText: { color: '#fff', fontWeight: '600', + textAlign: 'center', }, screen: { - alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 12, }, subtitle: { color: '#6b7280', - textAlign: 'center', }, title: { color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontSize: 24, + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx index 732205a0..c5b55336 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx +++ b/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx @@ -1,61 +1,79 @@ import { Directory, File, Paths } from 'expo-file-system' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useMemo, useState } from 'react' +import { + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' export default function App() { - const noteFile = useMemo(() => new File(new Directory(Paths.cache, 'notes'), 'daily.txt'), []) - const [text, setText] = useState('No note loaded.') + const [draft, setDraft] = useState('') + const [status, setStatus] = useState('Loading notes…') - const save = async () => { - const dir = new Directory(Paths.cache, 'notes') - dir.create({ idempotent: true, intermediates: true }) - noteFile.write('Expo SDK 56 file-system note') - setText(await noteFile.text()) - } + const noteFile = useMemo( + () => new File(new Directory(Paths.cache, 'notes'), 'daily.txt'), + [], + ) - const load = async () => { + const loadNote = async () => { try { - setText(await noteFile.text()) + const contents = noteFile.text() + setDraft(contents) + setStatus('Loaded saved note.') } catch { - setText('No note exists yet.') + setStatus('No saved note yet.') } } + const saveNote = async () => { + const dir = new Directory(Paths.cache, 'notes') + dir.create({ idempotent: true, intermediates: true }) + noteFile.write(draft) + setStatus('Saved.') + } + + useEffect(() => { + void loadNote() + }, []) + return ( - File note - {text} - Save - Load + Notes + + + Save + + {status} ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, + input: { + borderColor: '#d1d5db', + borderRadius: 10, borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + minHeight: 120, + padding: 12, + textAlignVertical: 'top', }, screen: { backgroundColor: '#fff', @@ -63,8 +81,8 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { - color: '#4b5563', + status: { + color: '#6b7280', }, title: { color: '#111827', diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx index f53640bf..78a4cc54 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx +++ b/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx @@ -1,27 +1,42 @@ import { Directory, File, Paths } from 'expo-file-system' -import * as LegacyFileSystem from 'expo-file-system/legacy' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +const PROFILE_DIR = new Directory(Paths.cache, 'profile') +const PROFILE_FILE = new File(PROFILE_DIR, 'profile.json') export default function App() { const [message, setMessage] = useState('Ready.') - const migrate = async () => { - const file = new File(Paths.cache, 'profile.json') - file.write(JSON.stringify({ name: 'Expo' })) - setMessage(await file.text()) + const saveProfile = async () => { + try { + PROFILE_DIR.create({ intermediates: true, idempotent: true }) + PROFILE_FILE.write(JSON.stringify({ name: 'Expo' })) + setMessage('Saved profile.') + } catch (error) { + setMessage(`Save failed: ${String(error)}`) + } } - const readLegacyUri = async (uri: string) => { - return LegacyFileSystem.readAsStringAsync(uri) + const loadProfile = async () => { + try { + const contents = PROFILE_FILE.text() + setMessage(contents) + } catch (error) { + setMessage(`Load failed: ${String(error)}`) + } } return ( - Filesystem migration + Filesystem helper {message} - Use object API - void readLegacyUri(new File(new Directory(Paths.cache), 'profile.json').uri)} style={styles.action}>Read legacy uri + + Save profile + + + Load profile + ) } @@ -37,21 +52,6 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, screen: { backgroundColor: '#fff', flex: 1, diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx index d27eef4e..529242cc 100644 --- a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx +++ b/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx @@ -1,58 +1,94 @@ import { Directory, File, Paths } from 'expo-file-system' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + ActivityIndicator, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' + +const REMOTE_URL = 'https://example.com/report.pdf' +const UPLOAD_ENDPOINT = 'https://example.com/api/upload' + +type Phase = 'idle' | 'downloading' | 'uploading' | 'done' | 'error' export default function App() { - const [status, setStatus] = useState('Idle.') + const [phase, setPhase] = useState('idle') + const [progress, setProgress] = useState(0) - const sync = async () => { + const transfer = async () => { + setPhase('downloading') + setProgress(0) try { - const downloads = new Directory(Paths.cache, 'downloads') + const downloads = new Directory(Paths.document, 'downloads') downloads.create({ idempotent: true, intermediates: true }) - const file = await File.downloadFileAsync('https://example.com/report.txt', downloads) + const file = await File.downloadFileAsync(REMOTE_URL, downloads) + setProgress(1) + + setPhase('uploading') const body = new FormData() - body.append('file', file as unknown as Blob) - await fetch('https://example.com/upload', { body, method: 'POST' }) - setStatus(`Uploaded ${file.name}`) - } catch (error) { - setStatus(error instanceof Error ? error.message : 'Sync failed.') + body.append('file', { + name: file.name, + type: 'application/pdf', + uri: file.uri, + } as unknown as Blob) + const response = await fetch(UPLOAD_ENDPOINT, { body, method: 'POST' }) + if (!response.ok) { + throw new Error(`Upload failed: ${response.status}`) + } + setPhase('done') + } catch { + setPhase('error') } } return ( - File sync - {status} - Sync + Sync report + {REMOTE_URL} + + {phase === 'downloading' || phase === 'uploading' ? ( + + + + {phase === 'downloading' + ? `Downloading ${Math.round(progress * 100)}%` + : 'Uploading…'} + + + ) : null} + + {phase === 'done' ? Upload complete. : null} + {phase === 'error' ? ( + Transfer failed. + ) : null} + + + Download & upload + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + error: { + color: '#b91c1c', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + progressRow: { + alignItems: 'center', + columnGap: 10, + flexDirection: 'row', }, screen: { backgroundColor: '#fff', @@ -60,9 +96,12 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { + status: { color: '#4b5563', }, + subtitle: { + color: '#6b7280', + }, title: { color: '#111827', fontSize: 20, diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx index c929f6d5..182d94be 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx @@ -1,48 +1,77 @@ +import { Directory, File, Paths } from 'expo-file-system' import * as MediaLibrary from 'expo-media-library' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' + +const GENERATED_IMAGE_URI = 'https://example.com/generated/poster.png' + +type SaveState = 'idle' | 'saving' | 'saved' | 'denied' export default function App() { - const [message, setMessage] = useState('Ready to save a generated photo.') + const [saveState, setSaveState] = useState('idle') - const requestSaveAccess = async () => { + const saveToLibrary = async () => { + setSaveState('saving') const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) - setMessage(permission.granted ? 'Write-only photo access granted.' : 'Photo save permission denied.') + if (!permission.granted) { + setSaveState('denied') + return + } + try { + const cache = new Directory(Paths.cache, 'posters') + cache.create({ idempotent: true, intermediates: true }) + const file = await File.downloadFileAsync(GENERATED_IMAGE_URI, cache) + await MediaLibrary.saveToLibraryAsync(file.uri) + setSaveState('saved') + } catch { + setSaveState('denied') + } } return ( - Save access - {message} - Request save access + Save poster + + + + {saveState === 'saved' ? ( + Saved to your photos. + ) : null} + {saveState === 'denied' ? ( + + Photo access is required to save this image. + + ) : null} + + + Save to photos + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + error: { + color: '#b91c1c', }, - media: { + preview: { backgroundColor: '#e5e7eb', borderRadius: 12, - height: 180, - overflow: 'hidden', + height: 220, width: '100%', }, screen: { @@ -51,7 +80,7 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { + status: { color: '#4b5563', }, title: { diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx index 9e13ad7e..8c20bb3e 100644 --- a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx +++ b/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx @@ -1,69 +1,102 @@ -import { File, Paths } from 'expo-file-system' +import { File } from 'expo-file-system' import * as MediaLibrary from 'expo-media-library' import { useState } from 'react' -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { Image, Pressable, StyleSheet, Text, View } from 'react-native' -const transparentPng = Uint8Array.from([ - 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, - 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137, 0, 0, 0, 13, 73, 68, 65, - 84, 120, 156, 99, 248, 255, 255, 63, 0, 5, 254, 2, 254, 167, 53, 129, 132, - 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130, -]) +const ALBUM_NAME = 'My Renders' +const LOCAL_IMAGE_URI = 'file:///tmp/render.png' + +type SaveState = 'idle' | 'saving' | 'saved' | 'error' export default function App() { - const [message, setMessage] = useState('No asset saved.') + const [saveState, setSaveState] = useState('idle') - const save = async () => { - const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) - if (!permission.granted) { - setMessage('Cannot save without photo permission.') - return - } - const file = new File(Paths.cache, 'generated-photo.png') - file.write(transparentPng) - if (!file.exists) { - setMessage('Generated file was not written.') - return - } - const asset = await MediaLibrary.Asset.create(file.uri) - const album = await MediaLibrary.Album.get('Exports') - if (album) { - await album.add(asset) - } else { - await MediaLibrary.Album.create('Exports', [asset], false) + const saveToAlbum = async () => { + setSaveState('saving') + try { + const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) + if (!permission.granted) { + setSaveState('error') + return + } + + const file = new File(LOCAL_IMAGE_URI) + if (!file.exists) { + setSaveState('error') + return + } + + const asset = await MediaLibrary.Asset.create(file.uri) + const album = await MediaLibrary.Album.get(ALBUM_NAME) + if (album) { + await album.add(asset) + } else { + await MediaLibrary.Album.create(ALBUM_NAME, [asset], false) + } + + setSaveState('saved') + } catch { + setSaveState('error') } - setMessage(await asset.getFilename()) } return ( - Media asset - {message} - Save asset + Save render + Album: {ALBUM_NAME} + + + + {saveState === 'saved' ? ( + Added to {ALBUM_NAME}. + ) : null} + {saveState === 'error' ? ( + Could not save the image. + ) : null} + + + Save to album + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, + error: { + color: '#b91c1c', + }, + preview: { + backgroundColor: '#e5e7eb', + borderRadius: 12, + height: 220, + width: '100%', + }, screen: { backgroundColor: '#fff', flex: 1, padding: 20, rowGap: 12, }, - subtitle: { + status: { color: '#4b5563', }, + subtitle: { + color: '#6b7280', + }, title: { color: '#111827', fontSize: 20, diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx index 4e908c19..ce026c00 100644 --- a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx +++ b/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx @@ -1,64 +1,142 @@ import * as Calendar from 'expo-calendar' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useRef, useState } from 'react' +import { + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' + +type CalendarOption = { + id: string + title: string +} export default function App() { - const [message, setMessage] = useState('No event created.') + const [calendars, setCalendars] = useState([]) + const [selectedId, setSelectedId] = useState(null) + const [eventTitle, setEventTitle] = useState('') + const [status, setStatus] = useState('') - const create = async () => { + const calendarsRef = useRef([]) + + const loadCalendars = async () => { const permission = await Calendar.requestCalendarPermissions() if (!permission.granted) { - setMessage('Calendar permission denied.') + setStatus('Calendar permission required.') return } - const calendars = await Calendar.getCalendars(Calendar.EntityTypes.EVENT) - const calendar = calendars.find((item) => item.allowsModifications) + + const available = await Calendar.getCalendars(Calendar.EntityTypes.EVENT) + const writable = available.filter((calendar) => calendar.allowsModifications) + if (writable.length === 0) { + setStatus('No writable calendar available.') + return + } + + calendarsRef.current = writable + setCalendars( + writable.map((calendar) => ({ id: calendar.id, title: calendar.title })), + ) + setSelectedId(writable[0].id) + } + + const createEvent = async () => { + const calendar = calendarsRef.current.find((item) => item.id === selectedId) if (!calendar) { - setMessage('No writable calendar available.') + setStatus('Select a writable calendar first.') return } - const event = await calendar.createEvent({ - endDate: new Date(Date.now() + 60 * 60 * 1000), + + await calendar.createEvent({ + title: eventTitle, startDate: new Date(), - title: 'Expo planning', + endDate: new Date(Date.now() + 60 * 60 * 1000), }) - setMessage(event.id) + setStatus('Event created.') } + useEffect(() => { + void loadCalendars() + }, []) + return ( - Calendar - {message} - Create event + New event + + + {calendars.map((calendar) => { + const isActive = calendar.id === selectedId + return ( + setSelectedId(calendar.id)} + style={[styles.chip, isActive && styles.chipActive]} + > + + {calendar.title} + + + ) + })} + + + + + + Create event + + + {status ? {status} : null} ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, + calendarRow: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 8, + }, + chip: { + borderColor: '#94a3b8', + borderRadius: 999, borderWidth: 1, - padding: 14, - width: '100%', + paddingHorizontal: 12, + paddingVertical: 6, + }, + chipActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + chipText: { + color: '#334155', + fontWeight: '600', + }, + chipTextActive: { + color: '#fff', + }, + input: { + borderColor: '#d1d5db', + borderRadius: 10, + borderWidth: 1, + padding: 12, }, screen: { backgroundColor: '#fff', @@ -66,8 +144,8 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { - color: '#4b5563', + status: { + color: '#6b7280', }, title: { color: '#111827', diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx index bda1d727..b8d29168 100644 --- a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx @@ -1,69 +1,139 @@ import * as Contacts from 'expo-contacts' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + FlatList, + Image, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' + +type ContactRow = { + id: string + name: string + email?: string + imageUri?: string +} export default function App() { - const [contacts, setContacts] = useState< - Array<{ fullName?: string | null; id: string }> - >([]) - const [message, setMessage] = useState('Contacts not loaded.') + const [contacts, setContacts] = useState([]) + const [loaded, setLoaded] = useState(false) + const [denied, setDenied] = useState(false) - const load = async () => { + const loadContacts = async () => { const permission = await Contacts.requestPermissionsAsync() if (!permission.granted) { - setMessage('Contacts permission denied.') + setDenied(true) return } + const result = await Contacts.Contact.getAllDetails( [ Contacts.ContactField.FULL_NAME, Contacts.ContactField.EMAILS, Contacts.ContactField.IMAGE, ], - { limit: 20 } + { limit: 50 }, + ) + + setContacts( + result.map((contact) => ({ + id: contact.id, + name: contact.fullName ?? 'Unnamed contact', + email: contact.emails?.[0]?.email, + imageUri: contact.image?.uri, + })), + ) + setLoaded(true) + } + + if (denied) { + return ( + + Contacts + Contacts permission was denied. + ) - setContacts(result.map((contact) => ({ - fullName: contact.fullName, - id: contact.id, - }))) - setMessage(result.length ? 'Contacts loaded.' : 'No contacts available.') } return ( - + Contacts - {message} - {contacts.map((contact) => {contact.fullName ?? 'Unnamed contact'})} - Load contacts - + + {!loaded ? ( + + Load contacts + + ) : ( + item.id} + ListEmptyComponent={ + No contacts found. + } + renderItem={({ item }) => ( + + {item.imageUri ? ( + + ) : ( + + )} + + {item.name} + {item.email ? ( + {item.email} + ) : null} + + + )} + /> + )} + ) } const styles = StyleSheet.create({ - action: { + avatar: { + backgroundColor: '#e5e7eb', + borderRadius: 20, + height: 40, + width: 40, + }, + avatarPlaceholder: { + backgroundColor: '#cbd5e1', + }, + button: { + alignSelf: 'flex-start', backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + centered: { + alignItems: 'center', + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + padding: 20, + rowGap: 8, + }, + email: { + color: '#6b7280', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + name: { + color: '#111827', + fontWeight: '600', + }, + row: { + alignItems: 'center', + columnGap: 12, + flexDirection: 'row', + paddingVertical: 8, }, screen: { backgroundColor: '#fff', @@ -72,7 +142,7 @@ const styles = StyleSheet.create({ rowGap: 12, }, subtitle: { - color: '#4b5563', + color: '#6b7280', }, title: { color: '#111827', diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx index 5e43ade1..4c11a331 100644 --- a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx +++ b/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx @@ -1,57 +1,77 @@ import { setAudioModeAsync, useAudioPlayer, useAudioPlayerStatus } from 'expo-audio' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect } from 'react' +import { AppState, Pressable, StyleSheet, Text, View } from 'react-native' + +const SOUND_URL = 'https://example.com/preview.mp3' export default function App() { - const player = useAudioPlayer('https://example.com/preview.mp3', { updateInterval: 250 }) + const player = useAudioPlayer(SOUND_URL) const status = useAudioPlayerStatus(player) + const isPlaying = status.playing useEffect(() => { - void setAudioModeAsync({ playsInSilentMode: true }) - const sub = AppState.addEventListener('change', (state) => { + void setAudioModeAsync({ + playsInSilentMode: true, + interruptionMode: 'mixWithOthers', + }) + const subscription = AppState.addEventListener('change', (state) => { if (state !== 'active') player.pause() }) return () => { player.pause() - sub.remove() + subscription.remove() } }, [player]) + const togglePlayback = () => { + // Play or pause the audio preview. + if (player.playing) { + player.pause() + } else { + player.play() + } + } + return ( Audio preview - {status.playing ? 'Playing' : 'Paused'} - player.play()} style={styles.action}>Play - player.pause()} style={styles.action}>Pause + {SOUND_URL} + + + + {isPlaying ? 'Playing' : 'Paused'} + + + + {isPlaying ? 'Pause' : 'Play'} + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + dot: { + borderRadius: 6, + height: 12, + width: 12, + }, + dotIdle: { + backgroundColor: '#cbd5e1', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + dotPlaying: { + backgroundColor: '#16a34a', }, screen: { backgroundColor: '#fff', @@ -59,9 +79,17 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { + status: { color: '#4b5563', }, + statusRow: { + alignItems: 'center', + columnGap: 8, + flexDirection: 'row', + }, + subtitle: { + color: '#6b7280', + }, title: { color: '#111827', fontSize: 20, diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx index 3b434103..035f8f22 100644 --- a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx +++ b/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx @@ -1,49 +1,71 @@ import { useVideoPlayer, VideoView } from 'expo-video' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { AppState, Pressable, StyleSheet, Text, View } from 'react-native' +const VIDEO_URL = 'https://example.com/clip.mp4' + export default function App() { - const player = useVideoPlayer('https://example.com/demo.mp4', (nextPlayer) => { + const [muted, setMuted] = useState(true) + const [looping, setLooping] = useState(true) + + const player = useVideoPlayer(VIDEO_URL, (nextPlayer) => { nextPlayer.loop = true nextPlayer.muted = true }) useEffect(() => { - const sub = AppState.addEventListener('change', (state) => { + player.muted = muted + }, [player, muted]) + + useEffect(() => { + player.loop = looping + }, [player, looping]) + + useEffect(() => { + const subscription = AppState.addEventListener('change', (state) => { if (state !== 'active') player.pause() }) return () => { player.pause() - sub.remove() + subscription.remove() } }, [player]) return ( - Video - - player.play()} style={styles.action}>Play + Video player + + + + + setMuted((current) => !current)} + > + + {muted ? 'Muted' : 'Sound on'} + + + + setLooping((current) => !current)} + > + + {looping ? 'Looping' : 'No loop'} + + + + + {VIDEO_URL} ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + controls: { + flexDirection: 'row', + gap: 8, }, screen: { backgroundColor: '#fff', @@ -51,9 +73,38 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, + subtitle: { + color: '#6b7280', + }, + surface: { + alignItems: 'center', + backgroundColor: '#111827', + borderRadius: 12, + height: 200, + justifyContent: 'center', + width: '100%', + }, title: { color: '#111827', fontSize: 20, fontWeight: '700', }, + toggle: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + toggleActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + toggleText: { + color: '#334155', + fontWeight: '600', + }, + toggleTextActive: { + color: '#fff', + }, }) diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx index 5f91608d..ff7027fa 100644 --- a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx +++ b/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx @@ -1,25 +1,45 @@ import { Image } from 'expo-image' import { useVideoPlayer, type VideoThumbnail } from 'expo-video' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +const VIDEO_URL = 'https://example.com/demo.mp4' export default function App() { - const player = useVideoPlayer('https://example.com/demo.mp4') + const player = useVideoPlayer(VIDEO_URL) const [thumbnail, setThumbnail] = useState(null) const [message, setMessage] = useState('No thumbnail.') const generate = async () => { - const thumbnails = await player.generateThumbnailsAsync([1, 3], { maxWidth: 480 }) - const first = thumbnails[0] - setThumbnail(first ?? null) - setMessage(first ? `Generated at ${first.actualTime}s` : 'Thumbnail unavailable.') + try { + const thumbnails = await player.generateThumbnailsAsync([1, 3], { + maxWidth: 480, + }) + const first = thumbnails[0] + if (!first) { + setThumbnail(null) + setMessage('No thumbnails generated.') + return + } + setThumbnail(first) + setMessage(`Generated at ${first.requestedTime}s.`) + } catch (error) { + setThumbnail(null) + setMessage(`Failed: ${String(error)}`) + } } return ( Thumbnail - {thumbnail ? : {message}} - Generate + {thumbnail ? ( + + ) : ( + {message} + )} + + Generate + ) } @@ -35,19 +55,10 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, media: { backgroundColor: '#e5e7eb', borderRadius: 12, height: 180, - overflow: 'hidden', width: '100%', }, screen: { diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx index 42d90cd9..8e797144 100644 --- a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx +++ b/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx @@ -1,59 +1,93 @@ import * as Updates from 'expo-updates' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { + ActivityIndicator, + Pressable, + StyleSheet, + Text, + View, +} from 'react-native' export default function App() { - const updateState = Updates.useUpdates() - const [message, setMessage] = useState('Check for updates.') + const { + currentlyRunning, + isDownloading, + downloadProgress, + isUpdateAvailable, + isUpdatePending, + downloadError, + } = Updates.useUpdates() + const [status, setStatus] = useState( + currentlyRunning.isEmbeddedLaunch ? 'Running embedded build.' : 'Up to date.', + ) - const apply = async () => { - if (!updateState.isUpdatePending) { - setMessage(updateState.downloadError?.message ?? 'No downloaded update to apply.') - return + const checkForUpdate = async () => { + setStatus('Checking…') + try { + const update = await Updates.checkForUpdateAsync() + if (!update.isAvailable) { + setStatus('Up to date.') + return + } + setStatus('Downloading…') + await Updates.fetchUpdateAsync() + await Updates.reloadAsync({ + reloadScreenOptions: { + backgroundColor: '#111827', + fade: true, + }, + }) + // Execution does not reliably continue after reloadAsync resolves. + } catch (error) { + setStatus(error instanceof Error ? error.message : 'Update failed.') } - await Updates.reloadAsync({ - reloadScreenOptions: { - backgroundColor: '#111827', - fade: true, - }, - }) } return ( - Updates - {updateState.isDownloading ? `Downloading ${Math.round((updateState.downloadProgress ?? 0) * 100)}%` : message} - {updateState.currentlyRunning.isEmbeddedLaunch ? 'Embedded launch' : 'Update launch'} - Apply update + App updates + + {isDownloading ? ( + + + + Downloading {Math.round((downloadProgress ?? 0) * 100)}% + + + ) : ( + + {downloadError + ? downloadError.message + : isUpdatePending + ? 'Update ready. Reloading…' + : isUpdateAvailable + ? 'Update available.' + : status} + + )} + + + Check for updates + ) } const styles = StyleSheet.create({ - action: { + button: { backgroundColor: '#111827', borderRadius: 10, paddingHorizontal: 14, paddingVertical: 10, }, - actionText: { + buttonText: { color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + progressRow: { + alignItems: 'center', + columnGap: 10, + flexDirection: 'row', }, screen: { backgroundColor: '#fff', @@ -61,7 +95,7 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { + status: { color: '#4b5563', }, title: { diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx b/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx index fa825f63..ea4e919b 100644 --- a/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx +++ b/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx @@ -1,53 +1,85 @@ import * as Updates from 'expo-updates' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' + +const CHANNELS = ['production', 'staging', 'beta'] as const + +type Channel = (typeof CHANNELS)[number] export default function App() { - const [cohort, setCohort] = useState<'default' | 'beta'>('default') - const [message, setMessage] = useState('Default updates.') + const [channel, setChannel] = useState('production') + const [status, setStatus] = useState('') - const select = async (next: 'default' | 'beta') => { - setCohort(next) - Updates.setUpdateRequestHeadersOverride(next === 'default' ? null : { 'expo-channel-name': 'beta' }) - const result = await Updates.checkForUpdateAsync() - setMessage(result.isAvailable ? 'Update available for cohort.' : 'No update for cohort.') + const selectChannel = async (next: Channel) => { + setChannel(next) + setStatus(`Checking ${next}…`) + try { + Updates.setUpdateRequestHeadersOverride( + next === 'production' ? null : { 'expo-channel-name': next }, + ) + const result = await Updates.checkForUpdateAsync() + setStatus( + result.isAvailable + ? `Update available on ${next}.` + : `No update on ${next}.`, + ) + } catch (error) { + setStatus(error instanceof Error ? error.message : 'Update check failed.') + } } return ( - Update cohort - {cohort}: {message} - select('beta')} style={styles.action}>Beta - select('default')} style={styles.action}>Default + Release channel + + + {CHANNELS.map((option) => { + const isActive = option === channel + return ( + selectChannel(option)} + style={[styles.chip, isActive && styles.chipActive]} + > + + {option} + + + ) + })} + + + Active channel: {channel} + {status ? {status} : null} ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', + channelRow: { + flexDirection: 'row', + gap: 8, }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, + chip: { + borderColor: '#94a3b8', + borderRadius: 999, borderWidth: 1, - padding: 14, - width: '100%', + paddingHorizontal: 12, + paddingVertical: 6, + }, + chipActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + chipText: { + color: '#334155', + fontWeight: '600', + textTransform: 'capitalize', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + chipTextActive: { + color: '#fff', }, screen: { backgroundColor: '#fff', @@ -55,6 +87,9 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, + status: { + color: '#6b7280', + }, subtitle: { color: '#4b5563', }, diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx index b38ba53d..77899430 100644 --- a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx @@ -1,38 +1,69 @@ import { GlassView, isGlassEffectAPIAvailable } from 'expo-glass-effect' import { NavigationBar, addVisibilityListener } from 'expo-navigation-bar' import { StatusBar } from 'expo-status-bar' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useEffect, useState } from 'react' +import { Platform, Pressable, StyleSheet, Text, View } from 'react-native' + +type BarStyle = 'light' | 'dark' export default function App() { - const [visible, setVisible] = useState('unknown') + const [barStyle, setBarStyle] = useState('dark') + const [glass, setGlass] = useState(false) const canUseGlass = isGlassEffectAPIAvailable() useEffect(() => { - StatusBar.setStyle('light', true) - if (Platform.OS !== 'android') return () => StatusBar.setStyle('auto', true) - NavigationBar.setStyle('dark') - const sub = addVisibilityListener((event) => setVisible(event.visibility)) + StatusBar.setStyle(barStyle, true) + if (Platform.OS !== 'android') { + return () => { + StatusBar.setStyle('auto', true) + } + } + NavigationBar.setStyle(barStyle) + const subscription = addVisibilityListener(() => {}) return () => { - sub.remove() + subscription.remove() StatusBar.setStyle('auto', true) NavigationBar.setStyle('auto') } - }, []) + }, [barStyle]) return ( - - {Platform.OS === 'android' ? : null} - System bars - Navigation bar: {visible} - {canUseGlass ? ( - - Liquid Glass controls available + + {Platform.OS === 'android' ? : null} + Appearance + + + + setBarStyle((current) => (current === 'dark' ? 'light' : 'dark')) + } + > + Bar style: {barStyle} + + + setGlass((current) => !current)} + > + + {glass ? 'Glass on' : 'Glass off'} + + + + + {glass && canUseGlass ? ( + + Liquid Glass surface ) : ( - - Liquid Glass fallback + + + {glass + ? 'Liquid Glass not supported on this platform.' + : 'Controls the system status and navigation bars.'} + )} @@ -40,17 +71,12 @@ export default function App() { } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + controls: { + flexDirection: 'row', + flexWrap: 'wrap', + gap: 8, }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { + glassCard: { backgroundColor: '#f9fafb', borderColor: '#e5e7eb', borderRadius: 12, @@ -58,13 +84,6 @@ const styles = StyleSheet.create({ padding: 14, width: '100%', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, screen: { backgroundColor: '#fff', flex: 1, @@ -72,11 +91,29 @@ const styles = StyleSheet.create({ rowGap: 12, }, subtitle: { - color: '#4b5563', + color: '#6b7280', }, title: { color: '#111827', fontSize: 20, fontWeight: '700', }, + toggle: { + borderColor: '#94a3b8', + borderRadius: 999, + borderWidth: 1, + paddingHorizontal: 12, + paddingVertical: 6, + }, + toggleActive: { + backgroundColor: '#0f172a', + borderColor: '#0f172a', + }, + toggleText: { + color: '#334155', + fontWeight: '600', + }, + toggleTextActive: { + color: '#fff', + }, }) diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx index d075ec12..931c71c5 100644 --- a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx @@ -1,35 +1,24 @@ -import { Pressable, StyleSheet, Text, View } from 'react-native' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( - Build properties - Replace this scaffold with the requested Expo implementation. - - Start - + Build properties audit + + Native build configuration is managed in app.config.ts. + ) } const styles = StyleSheet.create({ - button: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - buttonText: { - color: '#fff', - fontWeight: '600', - }, screen: { alignItems: 'center', backgroundColor: '#fff', flex: 1, justifyContent: 'center', padding: 20, - rowGap: 10, + rowGap: 8, }, subtitle: { color: '#6b7280', @@ -38,7 +27,6 @@ const styles = StyleSheet.create({ title: { color: '#111827', fontSize: 20, - fontWeight: '600', - textAlign: 'center', + fontWeight: '700', }, }) diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts index d19cd3af..ccf06e13 100644 --- a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts +++ b/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts @@ -12,8 +12,6 @@ export default { }, ios: { buildReactNativeFromSource: false, - ccacheEnabled: true, - forceStaticLinking: ['RNFBApp'], useFrameworks: 'static', }, }, diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx index 979e246e..2bfccec7 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx @@ -1,55 +1,30 @@ -import { Button, Host, RNHostView, Text as UIText } from '@expo/ui' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { Host, RNHostView, Text as UIText } from '@expo/ui' +import { StyleSheet, Text, View } from 'react-native' export default function App() { return ( - - Native settings - - React Native child intentionally hosted + + Account + Signed in as + jordan@example.com + + + Manage your profile and notification settings. + + ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + hint: { + color: '#6b7280', }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + hintWrapper: { + paddingTop: 8, }, screen: { - backgroundColor: '#fff', flex: 1, padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', }, }) diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx index 4e9102bc..1fd88b11 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx @@ -1,58 +1,25 @@ -import { Button, Column, Host, Row, Switch, Text as UIText } from '@expo/ui' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { Column, Host, Row, Switch, Text as UIText } from '@expo/ui' +import { useState } from 'react' export default function App() { - const [enabled, setEnabled] = useState(false) + const [pushEnabled, setPushEnabled] = useState(true) + const [emailEnabled, setEmailEnabled] = useState(false) + return ( - Preferences - Sync - + Notifications + + + Push notifications + + + + + Email updates + + ) } - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx index 350319b4..21b8a893 100644 --- a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx @@ -1,18 +1,30 @@ -import { BottomSheet, BottomSheetModalProvider, BottomSheetView } from '@expo/ui/community/bottom-sheet' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { BottomSheet, BottomSheetView } from '@expo/ui/community/bottom-sheet' +import { useRef } from 'react' +import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const ref = useRef(null) + const sheetRef = useRef(null) + return ( - - - ref.current?.present()} style={styles.action}>Open sheet - {}}> - Sheet content - - - + + Trip details + sheetRef.current?.expand()} + style={styles.action} + > + Show summary + + + + + Summary + 3 nights · 2 guests · $640 total + sheetRef.current?.close()} style={styles.action}> + Done + + + + ) } @@ -27,33 +39,27 @@ const styles = StyleSheet.create({ color: '#fff', fontWeight: '600', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, screen: { backgroundColor: '#fff', flex: 1, padding: 20, rowGap: 12, }, + sheetContent: { + padding: 20, + rowGap: 6, + }, + sheetTitle: { + color: '#111827', + fontSize: 18, + fontWeight: '700', + }, subtitle: { color: '#4b5563', }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx index 548a5e56..c50fd338 100644 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx @@ -1,56 +1,70 @@ -import { DateTimePicker } from '@expo/ui/community/datetime-picker' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import DateTimePicker from '@expo/ui/community/datetime-picker' +import { useState } from 'react' +import { StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { + const [name, setName] = useState('') const [date, setDate] = useState(new Date()) + return ( - Date - next && setDate(next)} /> - {date.toDateString()} + New reservation + + + Guest name + + + + + Date + { + if (selectedDate) { + setDate(selectedDate) + } + }} + /> + {date.toDateString()} + ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', + field: { + rowGap: 6, }, - card: { + input: { backgroundColor: '#f9fafb', borderColor: '#e5e7eb', - borderRadius: 12, + borderRadius: 10, borderWidth: 1, - padding: 14, - width: '100%', + paddingHorizontal: 12, + paddingVertical: 12, + }, + inputText: { + color: '#111827', }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + label: { + color: '#6b7280', + fontSize: 13, }, screen: { backgroundColor: '#fff', flex: 1, padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx index 6be41e00..6dddcd28 100644 --- a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx +++ b/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx @@ -1,56 +1,93 @@ -import { DateTimePicker } from '@expo/ui/community/datetime-picker' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import DateTimePicker from '@expo/ui/community/datetime-picker' +import { useState } from 'react' +import { Platform, StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { - const [date, setDate] = useState(new Date()) + const [title, setTitle] = useState('') + const [startsAt, setStartsAt] = useState(new Date()) + + const updateStartsAt = (next?: Date) => { + if (next) { + setStartsAt(next) + } + } + return ( - Supported picker - setDate(next)} /> - Unsupported native props are intentionally omitted. + New appointment + + + Title + + + + + Starts + {Platform.OS === 'ios' ? ( + updateStartsAt(next)} + /> + ) : ( + + updateStartsAt(next)} + /> + updateStartsAt(next)} + /> + + Combined date and time selection is not available on this platform; pick each separately. + + + )} + ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + fallback: { + color: '#6b7280', + fontSize: 13, + }, + field: { + rowGap: 6, }, - actionText: { - color: '#fff', - fontWeight: '600', + inlineRow: { + rowGap: 8, }, - card: { + input: { backgroundColor: '#f9fafb', borderColor: '#e5e7eb', - borderRadius: 12, + borderRadius: 10, borderWidth: 1, - padding: 14, - width: '100%', + paddingHorizontal: 12, + paddingVertical: 12, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + label: { + color: '#6b7280', + fontSize: 13, }, screen: { backgroundColor: '#fff', flex: 1, padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', + rowGap: 16, }, title: { color: '#111827', - fontSize: 20, + fontSize: 24, fontWeight: '700', }, }) diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx index 9ff3d629..3d0a0030 100644 --- a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx @@ -1,45 +1,55 @@ import { PagerView } from '@expo/ui/community/pager-view' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { useState } from 'react' +import { StyleSheet, Text, View } from 'react-native' + +const PAGES = [ + { key: 'welcome', title: 'Welcome', body: 'Track your habits in one place.' }, + { key: 'reminders', title: 'Reminders', body: 'Get nudged at the right time.' }, + { key: 'insights', title: 'Insights', body: 'See your streaks grow.' }, +] export default function App() { const [page, setPage] = useState(0) + return ( - setPage(event.nativeEvent.position)} style={styles.media}> - One - Two + setPage(event.nativeEvent.position)} + style={styles.pager} + > + {PAGES.map((item) => ( + + {item.title} + {item.body} + + ))} - Page {page + 1} + + + {page + 1} / {PAGES.length} + ) } const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, + body: { + color: '#4b5563', + textAlign: 'center', }, - actionText: { - color: '#fff', - fontWeight: '600', + indicator: { + color: '#6b7280', + textAlign: 'center', }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', + page: { + alignItems: 'center', + justifyContent: 'center', + padding: 24, + rowGap: 8, }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', + pager: { + flex: 1, }, screen: { backgroundColor: '#fff', @@ -47,12 +57,9 @@ const styles = StyleSheet.create({ padding: 20, rowGap: 12, }, - subtitle: { - color: '#4b5563', - }, title: { color: '#111827', - fontSize: 20, + fontSize: 22, fontWeight: '700', }, }) diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx index 1386bfd1..a34d1dce 100644 --- a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx @@ -1,54 +1,16 @@ -import { Host, Text as MaterialText, useMaterialColors } from '@expo/ui/jetpack-compose' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { Column, Host, Text as MaterialText, useMaterialColors } from '@expo/ui/jetpack-compose' export default function App() { - const colors = useMaterialColors({ seedColor: '#2563eb' }) + const colors = useMaterialColors() + return ( - Material themed text + + Today + + You have 3 tasks due + + ) } - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx index 3730c83b..e8eca3ec 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -1,54 +1,31 @@ -import { Host, TextInput, useNativeState } from '@expo/ui' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Platform, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' +import { Host, Text as UIText, TextInput, useNativeState } from '@expo/ui' +import { useEffect, useState } from 'react' export default function App() { - const value = useNativeState('Expo UI') + const query = useNativeState('') + const [preview, setPreview] = useState('') + + useEffect(() => { + query.onChange = (value: string) => { + setPreview(value) + } + return () => { + query.onChange = null + } + }, [query]) + return ( - { value.value = next }} placeholder="Name" /> + Search + { + query.value = next + }} + placeholder="Type to filter" + autoCapitalize="none" + /> + {preview ? `Searching for "${preview}"` : 'Start typing above'} ) } - -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx index e019a308..9ab6140b 100644 --- a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx @@ -1,55 +1,50 @@ +import { Host as AndroidHost, Column as AndroidColumn, Text as AndroidText } from '@expo/ui/jetpack-compose' +import { + background as androidBackground, + clip as androidClip, + shadow as androidShadow, + Shapes, +} from '@expo/ui/jetpack-compose/modifiers' +import { Host as IOSHost, Column as IOSColumn, Text as IOSText } from '@expo/ui/swift-ui' +import { + background as iosBackground, + cornerRadius as iosCornerRadius, + shadow as iosShadow, +} from '@expo/ui/swift-ui/modifiers' import { Platform } from 'react-native' -import { Host as AndroidHost, Text as AndroidText } from '@expo/ui/jetpack-compose' -import { Host as IOSHost, Text as IOSText } from '@expo/ui/swift-ui' -import { background } from '@expo/ui/swift-ui/modifiers' -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { AppState, Image, Linking, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native' export default function App() { if (Platform.OS === 'ios') { - return iOS native UI + return ( + + Featured + + Weekly digest + Your top stories, every Monday. + + + ) } - return Android native UI -} -const styles = StyleSheet.create({ - action: { - backgroundColor: '#111827', - borderRadius: 10, - paddingHorizontal: 14, - paddingVertical: 10, - }, - actionText: { - color: '#fff', - fontWeight: '600', - }, - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 14, - width: '100%', - }, - media: { - backgroundColor: '#e5e7eb', - borderRadius: 12, - height: 180, - overflow: 'hidden', - width: '100%', - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 12, - }, - subtitle: { - color: '#4b5563', - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '700', - }, -}) + return ( + + Featured + + Weekly digest + Your top stories, every Monday. + + + ) +} From 91ff567009881d3f64e6be8f0c389b9623fbe42e Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 01:01:34 +0400 Subject: [PATCH 15/32] fix(evals): exercise Button in expo-ui/02 and real visibility listener in expo-sdk/25 - expo-ui/02: add a Reset button (RN in starter, @expo/ui Button in reference) so the universal-layout-primitives requirement that lists Button is genuinely satisfied - expo-sdk/25: drive navigation-bar visibility state from addVisibilityListener and render it, instead of a no-op callback Co-Authored-By: Claude Opus 4.6 --- .../reference/App.tsx | 11 +++++++++- .../app/App.tsx | 21 ++++++++++++++++++- .../reference/App.tsx | 9 +++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx index 77899430..b62e14b2 100644 --- a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx +++ b/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx @@ -9,6 +9,9 @@ type BarStyle = 'light' | 'dark' export default function App() { const [barStyle, setBarStyle] = useState('dark') const [glass, setGlass] = useState(false) + const [navVisibility, setNavVisibility] = useState<'visible' | 'hidden'>( + 'visible', + ) const canUseGlass = isGlassEffectAPIAvailable() useEffect(() => { @@ -19,7 +22,9 @@ export default function App() { } } NavigationBar.setStyle(barStyle) - const subscription = addVisibilityListener(() => {}) + const subscription = addVisibilityListener((event) => { + setNavVisibility(event.visibility) + }) return () => { subscription.remove() StatusBar.setStyle('auto', true) @@ -33,6 +38,10 @@ export default function App() { {Platform.OS === 'android' ? : null} Appearance + {Platform.OS === 'android' ? ( + Navigation bar: {navVisibility} + ) : null} + { + setPushEnabled(true) + setEmailEnabled(false) + } + return ( Notifications @@ -18,11 +23,25 @@ export default function App() { Email updates + + + Reset to defaults + ) } const styles = StyleSheet.create({ + button: { + alignItems: 'center', + backgroundColor: '#111827', + borderRadius: 10, + paddingVertical: 12, + }, + buttonText: { + color: '#fff', + fontWeight: '600', + }, row: { alignItems: 'center', backgroundColor: '#f9fafb', diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx index 1fd88b11..769f10a2 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx @@ -1,10 +1,15 @@ -import { Column, Host, Row, Switch, Text as UIText } from '@expo/ui' +import { Button, Column, Host, Row, Switch, Text as UIText } from '@expo/ui' import { useState } from 'react' export default function App() { const [pushEnabled, setPushEnabled] = useState(true) const [emailEnabled, setEmailEnabled] = useState(false) + const handleReset = () => { + setPushEnabled(true) + setEmailEnabled(false) + } + return ( @@ -19,6 +24,8 @@ export default function App() { Email updates + + ) From 0f4b03d6e84eb4a48d1b42d31d4d55664346b7ac Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 01:10:15 +0400 Subject: [PATCH 16/32] fix(evals): QA-pass corrections to Expo references and requirements From the fresh-context review: - expo-ui/03, 08: use the documented default imports for BottomSheet and PagerView (were named imports) - expo-modules/06: add style prop to the AuditLabel wrapper Props so the consumer typechecks - expo-modules/05: drop the now-inaccurate "no types" comment in the solved reference - expo-router/05, 06: keep the scaffold's route-screen bodies in the reference (only the tabs _layout is under test) - expo-sdk/16, 19: drop requirements that referenced config files absent from inputs and reference (permission-plugin-note, config-plugin-fields) - expo-sdk/12: mention background remote notifications in the prompt so the background-remote plugin-option requirement maps to the scenario Co-Authored-By: Claude Opus 4.6 --- .../reference/App.tsx | 1 - .../reference/src/AuditLabel.tsx | 2 ++ .../reference/index.tsx | 16 ++++++++++++++-- .../reference/settings.tsx | 16 ++++++++++++++-- .../reference/index.tsx | 16 ++++++++++++++-- .../reference/settings.tsx | 16 ++++++++++++++-- .../prompt.md | 2 +- .../requirements.yaml | 2 -- .../requirements.yaml | 2 -- .../reference/App.tsx | 2 +- .../reference/App.tsx | 2 +- 11 files changed, 61 insertions(+), 16 deletions(-) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx index d6daad5b..ff5722e6 100644 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx +++ b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx @@ -7,7 +7,6 @@ export default function App() { const [battery, setBattery] = useState('loading…') useEffect(() => { - // No types here, so this call site is unchecked. DeviceAudit.getBatteryLabelAsync() .then((label: string) => setBattery(label)) .catch(() => setBattery('unavailable')) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx index b95931b0..7f00d1ad 100644 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx +++ b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx @@ -1,8 +1,10 @@ import { requireNativeViewManager } from 'expo-modules-core' +import type { StyleProp, ViewStyle } from 'react-native' type Props = { title: string onReady?: () => void + style?: StyleProp } export default requireNativeViewManager('AuditLabel') diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx index 4d398c68..87a7a2cd 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/index.tsx @@ -1,2 +1,14 @@ -import { Text } from 'react-native' -export default function Home() { return Home } +import { StyleSheet, Text, View } from 'react-native' + +export default function Home() { + return ( + + Home + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx index a21db765..fcc1d19a 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/reference/settings.tsx @@ -1,2 +1,14 @@ -import { Text } from 'react-native' -export default function Settings() { return Settings } +import { StyleSheet, Text, View } from 'react-native' + +export default function Settings() { + return ( + + Settings + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx index 4d398c68..87a7a2cd 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/index.tsx @@ -1,2 +1,14 @@ -import { Text } from 'react-native' -export default function Home() { return Home } +import { StyleSheet, Text, View } from 'react-native' + +export default function Home() { + return ( + + Home + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx index a21db765..fcc1d19a 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/settings.tsx @@ -1,2 +1,14 @@ -import { Text } from 'react-native' -export default function Settings() { return Settings } +import { StyleSheet, Text, View } from 'react-native' + +export default function Settings() { + return ( + + Settings + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, alignItems: 'center', justifyContent: 'center' }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md index f6f9187a..4ad9ebe6 100644 --- a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md +++ b/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md @@ -1 +1 @@ -Configure native notification settings (icon, color, default channel) for an Expo project using current SDK conventions. The project has notification configuration in app.config.ts that may need updating. \ No newline at end of file +Configure native notification settings (icon, color, default channel, and background remote notifications) for an Expo project using current SDK conventions. The project has notification configuration in app.config.ts that may need updating. \ No newline at end of file diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml index 525553ab..42e90cb6 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml +++ b/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml @@ -9,7 +9,5 @@ requirements: description: "Must pass granularPermissions containing photo when requesting photo-only access." - id: does-not-query-library-with-writeonly description: "Must not query/read the user library after requesting write-only permission." - - id: permission-plugin-note - description: "Must keep app/config code aligned with any granular permissions requested at runtime." - id: denied-fallback description: "Must render a deterministic denied-permission fallback." diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml index 917f8d70..3eb6c438 100644 --- a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml +++ b/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml @@ -11,5 +11,3 @@ requirements: description: "Must handle an empty data array with deterministic fallback UI." - id: no-query-on-mount-permission-prompt description: "Must not prompt for contacts permission on initial mount." - - id: config-plugin-fields-mentioned - description: "Must include or preserve contacts permission strings in app config when adding config files for the eval." diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx index 21b8a893..0ff83d01 100644 --- a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx +++ b/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx @@ -1,4 +1,4 @@ -import { BottomSheet, BottomSheetView } from '@expo/ui/community/bottom-sheet' +import BottomSheet, { BottomSheetView } from '@expo/ui/community/bottom-sheet' import { useRef } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx index 3d0a0030..f80370ee 100644 --- a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx +++ b/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx @@ -1,4 +1,4 @@ -import { PagerView } from '@expo/ui/community/pager-view' +import PagerView from '@expo/ui/community/pager-view' import { useState } from 'react' import { StyleSheet, Text, View } from 'react-native' From 53b5337d62bfa478b3abd06da5c0ef9e89b06c59 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 01:12:50 +0400 Subject: [PATCH 17/32] fix(evals): correct expo-ui/11 to a valid Jetpack Compose native-state screen useNativeState is exported from @expo/ui/jetpack-compose (Android) and cannot be combined with the universal TextInput. Reframe the eval to a Jetpack Compose screen: import Host/Text/TextField/useNativeState from @expo/ui/jetpack-compose, drive TextField via value/onValueChange on the native state's .value. Drop the listener-cleanup requirement (no such JS listener API exists on ObservableState) and add a no-React-state-mirror requirement. Verified against the SDK 56 useNativeState docs. Co-Authored-By: Claude Opus 4.6 --- .../prompt.md | 2 +- .../reference/App.tsx | 29 +++++++------------ .../requirements.yaml | 12 ++++---- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md index 84455481..02c849fa 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md @@ -1 +1 @@ -Build a text input in App.tsx using Expo UI that shares its value with the native layer and properly cleans up subscriptions. \ No newline at end of file +Build an Android Jetpack Compose search field in App.tsx using Expo UI whose text value is held in native state instead of React state. \ No newline at end of file diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx index e8eca3ec..0377dd38 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -1,31 +1,22 @@ -import { Host, Text as UIText, TextInput, useNativeState } from '@expo/ui' -import { useEffect, useState } from 'react' +import { + Host, + Text as ComposeText, + TextField, + useNativeState, +} from '@expo/ui/jetpack-compose' export default function App() { const query = useNativeState('') - const [preview, setPreview] = useState('') - - useEffect(() => { - query.onChange = (value: string) => { - setPreview(value) - } - return () => { - query.onChange = null - } - }, [query]) return ( - Search - { + Search + { query.value = next }} - placeholder="Type to filter" - autoCapitalize="none" /> - {preview ? `Searching for "${preview}"` : 'Start typing above'} ) } diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml index e74d8fee..f0214e91 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-native-state - description: "Must use useNativeState from @expo/ui for native-shared state." - - id: textinput-controlled - description: "Must wire TextInput value/onChangeText to the native state." - - id: native-state-listener-discipline - description: "Must clear native state listeners in cleanup." + description: "Must use useNativeState from @expo/ui/jetpack-compose for native-shared state." + - id: textfield-controlled + description: "Must wire the Expo UI TextField value and onValueChange to the native state value." - id: host-root - description: "Must render the Expo UI TextInput under Host." + description: "Must render the Expo UI TextField under the Jetpack Compose Host." + - id: no-react-state-mirror + description: "Must hold the field value in native state, not a parallel React useState." From e0ee037aae815050fa0c6812f65058e5a705877d Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 10:09:39 +0400 Subject: [PATCH 18/32] chore(evals): drop the expo-modules category entirely Remove all expo-modules evals and update the README table and whitepaper category table/total accordingly. Also corrects the expo-sdk (26 to 25) and expo-ui (12 to 9) counts that were stale after earlier eval removals. Suite total is now 137. Co-Authored-By: Claude Opus 4.6 --- README.md | 7 ++- .../app/App.tsx | 48 ------------------- .../app/INLINE_MODULES.md | 8 ---- .../app/app.json | 5 -- .../app/src/modules/DeviceAuditModule.kt | 17 ------- .../prompt.md | 1 - .../reference/App.tsx | 48 ------------------- .../reference/INLINE_MODULES.md | 8 ---- .../reference/app.json | 9 ---- .../src/modules/DeviceAuditModule.kt | 17 ------- .../requirements.yaml | 18 ------- .../app/App.tsx | 41 ---------------- .../app/index.ts | 3 -- .../app/modules/WeatherInlineModule.swift | 15 ------ .../prompt.md | 1 - .../reference/App.tsx | 41 ---------------- .../reference/index.ts | 3 -- .../modules/WeatherInlineModule.swift | 15 ------ .../requirements.yaml | 15 ------ .../app/App.tsx | 43 ----------------- .../app/src/NativeDeviceAudit.ts | 5 -- .../app/src/index.ts | 1 - .../prompt.md | 1 - .../reference/App.tsx | 42 ---------------- .../reference/src/NativeDeviceAudit.ts | 7 --- .../reference/src/index.ts | 2 - .../requirements.yaml | 15 ------ .../app/App.tsx | 39 --------------- .../app/ios/AuditLabelModule.swift | 7 --- .../app/ios/AuditLabelView.swift | 16 ------- .../app/src/AuditLabel.tsx | 7 --- .../prompt.md | 1 - .../reference/App.tsx | 39 --------------- .../reference/ios/AuditLabelModule.swift | 13 ----- .../reference/ios/AuditLabelView.swift | 25 ---------- .../reference/src/AuditLabel.tsx | 10 ---- .../requirements.yaml | 16 ------- .../app/App.tsx | 42 ---------------- .../app/build/index.d.ts | 1 - .../app/expo-module.config.json | 5 -- .../app/package.json | 18 ------- .../app/src/index.ts | 7 --- .../prompt.md | 1 - .../reference/App.tsx | 42 ---------------- .../reference/build/index.d.ts | 4 -- .../reference/expo-module.config.json | 5 -- .../reference/package.json | 19 -------- .../reference/src/index.ts | 7 --- .../requirements.yaml | 17 ------- .../app/App.tsx | 33 ------------- .../app/app.config.ts | 9 ---- .../app/plugin/withAuditPermissions.ts | 7 --- .../prompt.md | 1 - .../reference/App.tsx | 33 ------------- .../reference/app.config.ts | 11 ----- .../reference/plugin/withAuditPermissions.ts | 16 ------- .../requirements.yaml | 15 ------ .../app/App.tsx | 41 ---------------- .../app/expo-module.config.json | 5 -- .../app/src/AuditModule.ts | 7 --- .../app/src/index.ts | 7 --- .../prompt.md | 1 - .../reference/App.tsx | 41 ---------------- .../reference/expo-module.config.json | 5 -- .../reference/src/AuditModule.ts | 7 --- .../reference/src/AuditModule.web.ts | 9 ---- .../reference/src/index.ts | 7 --- .../requirements.yaml | 16 ------- evals/expo-modules/README.md | 31 ------------ paper/benchmark-methodology-whitepaper.tex | 7 ++- 70 files changed, 6 insertions(+), 1080 deletions(-) delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt delete mode 100644 evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift delete mode 100644 evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts delete mode 100644 evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx delete mode 100644 evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts delete mode 100644 evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts delete mode 100644 evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts delete mode 100644 evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml delete mode 100644 evals/expo-modules/README.md diff --git a/README.md b/README.md index 191b64d5..16520015 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,15 @@ A benchmark suite for evaluating how coding models solve real React Native tasks ## Available Evals -Groups map to top-level folders under `evals/`. The current suite contains 151 evals. +Groups map to top-level folders under `evals/`. The current suite contains 137 evals. | Group | Path | Evals | Status | | ----------------- | ------------------------- | ----: | ------ | | animation | `evals/animation` | 13 | Active | | async-state | `evals/async-state` | 13 | Active | -| expo-modules | `evals/expo-modules` | 10 | Active | | expo-router | `evals/expo-router` | 12 | Active | -| expo-sdk | `evals/expo-sdk` | 26 | Active | -| expo-ui | `evals/expo-ui` | 12 | Active | +| expo-sdk | `evals/expo-sdk` | 25 | Active | +| expo-ui | `evals/expo-ui` | 9 | Active | | lists | `evals/lists` | 18 | Active | | navigation | `evals/navigation` | 13 | Active | | react-native-apis | `evals/react-native-apis` | 9 | Active | diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx deleted file mode 100644 index eca68eb4..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/App.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { requireNativeModule } from 'expo' -import { StyleSheet, Text, View } from 'react-native' - -type DeviceAuditModule = { - source: string - getOsVersion(): string -} - -let osVersion = 'unknown' -let source = 'unavailable' - -try { - const DeviceAudit = requireNativeModule('DeviceAuditModule') - osVersion = DeviceAudit.getOsVersion() - source = DeviceAudit.source -} catch { - // Native module is not registered with the current build yet. -} - -export default function App() { - return ( - - Device Audit - OS version: {osVersion} - Module source: {source} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - row: { - color: '#374151', - }, -}) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md deleted file mode 100644 index e3549c43..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/INLINE_MODULES.md +++ /dev/null @@ -1,8 +0,0 @@ -# Inline Modules - -Native modules under `src/` are written with the Expo Modules Kotlin/Swift DSL so -they can be picked up as inline modules without publishing a separate package. - -Changes to the inline module configuration require regenerating the native project -(`npx expo prebuild`) or rebuilding the development client so the generated module -providers include the inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json b/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json deleted file mode 100644 index ade285c8..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/app.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "expo": { - "experiments": {} - } -} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt deleted file mode 100644 index 808e1bf1..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/app/src/modules/DeviceAuditModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package expo.modules.deviceaudit - -import android.os.Build -import expo.modules.kotlin.modules.Module -import expo.modules.kotlin.modules.ModuleDefinition - -class DeviceAuditModule : Module() { - override fun definition() = ModuleDefinition { - Name("DeviceAuditModule") - - Constant("source") { "inline" } - - Function("getOsVersion") { - Build.VERSION.RELEASE - } - } -} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md b/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md deleted file mode 100644 index c3c91779..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/prompt.md +++ /dev/null @@ -1 +0,0 @@ -The project has a native Kotlin module at src/modules/DeviceAuditModule.kt that should work as an Expo inline module. Make whatever changes are needed so the module is recognized by the Expo build system. \ No newline at end of file diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx deleted file mode 100644 index eca68eb4..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/App.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { requireNativeModule } from 'expo' -import { StyleSheet, Text, View } from 'react-native' - -type DeviceAuditModule = { - source: string - getOsVersion(): string -} - -let osVersion = 'unknown' -let source = 'unavailable' - -try { - const DeviceAudit = requireNativeModule('DeviceAuditModule') - osVersion = DeviceAudit.getOsVersion() - source = DeviceAudit.source -} catch { - // Native module is not registered with the current build yet. -} - -export default function App() { - return ( - - Device Audit - OS version: {osVersion} - Module source: {source} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - row: { - color: '#374151', - }, -}) diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md deleted file mode 100644 index e3549c43..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/INLINE_MODULES.md +++ /dev/null @@ -1,8 +0,0 @@ -# Inline Modules - -Native modules under `src/` are written with the Expo Modules Kotlin/Swift DSL so -they can be picked up as inline modules without publishing a separate package. - -Changes to the inline module configuration require regenerating the native project -(`npx expo prebuild`) or rebuilding the development client so the generated module -providers include the inline module. diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json deleted file mode 100644 index 45a79570..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "expo": { - "experiments": { - "inlineModules": { - "watchedDirectories": ["src/modules"] - } - } - } -} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt b/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt deleted file mode 100644 index 808e1bf1..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/reference/src/modules/DeviceAuditModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package expo.modules.deviceaudit - -import android.os.Build -import expo.modules.kotlin.modules.Module -import expo.modules.kotlin.modules.ModuleDefinition - -class DeviceAuditModule : Module() { - override fun definition() = ModuleDefinition { - Name("DeviceAuditModule") - - Constant("source") { "inline" } - - Function("getOsVersion") { - Build.VERSION.RELEASE - } - } -} diff --git a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml b/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml deleted file mode 100644 index 3003d1f6..00000000 --- a/evals/expo-modules/01-rn-expo-modules-inline-config/requirements.yaml +++ /dev/null @@ -1,18 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/INLINE_MODULES.md - - app/app.json - - app/src/modules/DeviceAuditModule.kt -requirements: - - id: inline-modules-enabled - description: "Must set expo.experiments.inlineModules in app config." - - id: watched-directory-valid - description: "Must place inline native files in a configured watched directory." - - id: no-overlapping-watched-dirs - description: "Must not include both a directory and its nested child in watchedDirectories." - - id: no-special-router-group-path - description: "Must not put special-character route groups such as app/(tabs) in watchedDirectories." - - id: module-dsl-used - description: "Must define the native module with Expo Module/ModuleDefinition DSL." diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx deleted file mode 100644 index 4360f08c..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/App.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import { WeatherInlineModule } from './index' - -let unit = 'unavailable' - -try { - unit = WeatherInlineModule.unit() -} catch { - // The native module did not load under the requested name. -} - -export default function App() { - return ( - - Weather - Temperature unit: {unit} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts deleted file mode 100644 index 942fed50..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift deleted file mode 100644 index d15a2f3f..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/app/modules/WeatherInlineModule.swift +++ /dev/null @@ -1,15 +0,0 @@ -import ExpoModulesCore - -public class WeatherModule: Module { - public func definition() -> ModuleDefinition { - Name("WeatherModule") - - Function("unit") { - return "celsius" - } - - Function("currentTemperature") { - return 21 - } - } -} diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md b/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md deleted file mode 100644 index ec2bea1e..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/prompt.md +++ /dev/null @@ -1 +0,0 @@ -The existing Swift inline module at modules/WeatherInlineModule.swift is not being picked up at runtime. Fix it so the module loads correctly and is accessible from JS. \ No newline at end of file diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx deleted file mode 100644 index 4360f08c..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/App.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import { WeatherInlineModule } from './index' - -let unit = 'unavailable' - -try { - unit = WeatherInlineModule.unit() -} catch { - // The native module did not load under the requested name. -} - -export default function App() { - return ( - - Weather - Temperature unit: {unit} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts deleted file mode 100644 index 942fed50..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export const WeatherInlineModule = requireNativeModule('WeatherInlineModule') diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift b/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift deleted file mode 100644 index d07dabf2..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/reference/modules/WeatherInlineModule.swift +++ /dev/null @@ -1,15 +0,0 @@ -import ExpoModulesCore - -public class WeatherInlineModule: Module { - public func definition() -> ModuleDefinition { - Name("WeatherInlineModule") - - Function("unit") { - return "celsius" - } - - Function("currentTemperature") { - return 21 - } - } -} diff --git a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml b/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml deleted file mode 100644 index f1675319..00000000 --- a/evals/expo-modules/03-rn-expo-modules-swift-name-match/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/index.ts - - app/modules/WeatherInlineModule.swift -requirements: - - id: swift-file-class-match - description: "Must make the Swift file name match the Swift module class name." - - id: swift-name-matches-class - description: "Must set Name(\"...\") to match the class name, or omit Name when the class name already matches." - - id: uses-expo-modules-core - description: "Must import ExpoModulesCore and conform to Module." - - id: swift-js-wrapper-same-name - description: "Must require the native module from JS using the same name." diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx deleted file mode 100644 index d6daad5b..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/App.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useEffect, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import { DeviceAudit } from './src' - -export default function App() { - const [battery, setBattery] = useState('loading…') - - useEffect(() => { - // No types here, so this call site is unchecked. - DeviceAudit.getBatteryLabelAsync() - .then((label: string) => setBattery(label)) - .catch(() => setBattery('unavailable')) - }, []) - - return ( - - Device Audit - Battery: {battery} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts deleted file mode 100644 index 7c564109..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/NativeDeviceAudit.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { NativeModulesProxy } from 'expo-modules-core' - -// Untyped access to the native module. Consumers reach into this proxy -// directly, so there is no type safety on the function surface. -export const DeviceAudit = NativeModulesProxy.DeviceAudit diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts deleted file mode 100644 index 83b0eb08..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/app/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { DeviceAudit } from './NativeDeviceAudit' diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md deleted file mode 100644 index f9ac6beb..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Create a typed JS wrapper module for the DeviceAudit native module so consumers have type-safe access to its functions. \ No newline at end of file diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx deleted file mode 100644 index ff5722e6..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/App.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useEffect, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import { DeviceAudit } from './src' - -export default function App() { - const [battery, setBattery] = useState('loading…') - - useEffect(() => { - DeviceAudit.getBatteryLabelAsync() - .then((label: string) => setBattery(label)) - .catch(() => setBattery('unavailable')) - }, []) - - return ( - - Device Audit - Battery: {battery} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts deleted file mode 100644 index 8dbfcf42..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/NativeDeviceAudit.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export type DeviceAuditModule = { - getBatteryLabelAsync(): Promise -} - -export const DeviceAudit = requireNativeModule('DeviceAudit') diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts deleted file mode 100644 index a2e9004d..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/reference/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { DeviceAudit } from './NativeDeviceAudit' -export type { DeviceAuditModule } from './NativeDeviceAudit' diff --git a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml b/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml deleted file mode 100644 index 9cb47540..00000000 --- a/evals/expo-modules/05-rn-expo-modules-require-native-module-wrapper/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/src/NativeDeviceAudit.ts - - app/src/index.ts -requirements: - - id: uses-require-native-module - description: "Must import requireNativeModule from expo-modules-core." - - id: typed-native-surface - description: "Must define a TypeScript type/interface for the native module surface." - - id: exports-js-helper - description: "Must export a JS helper instead of exposing an untyped native object everywhere." - - id: name-matches-native-module - description: "Must pass the exact native module name to requireNativeModule." diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx deleted file mode 100644 index 6798f6b7..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/App.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import AuditLabel from './src/AuditLabel' - -export default function App() { - return ( - - Audit Label - { - console.log('AuditLabel is ready') - }} - style={styles.label} - /> - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - label: { - height: 44, - width: 200, - }, -}) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift deleted file mode 100644 index d350a43f..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelModule.swift +++ /dev/null @@ -1,7 +0,0 @@ -import ExpoModulesCore - -public class AuditLabelModule: Module { - public func definition() -> ModuleDefinition { - Name("AuditLabel") - } -} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift deleted file mode 100644 index d6a17e12..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/ios/AuditLabelView.swift +++ /dev/null @@ -1,16 +0,0 @@ -import ExpoModulesCore - -final class AuditLabelView: ExpoView { - let label = UILabel() - - required init(appContext: AppContext? = nil) { - super.init(appContext: appContext) - label.numberOfLines = 0 - addSubview(label) - } - - override func layoutSubviews() { - super.layoutSubviews() - label.frame = bounds - } -} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx deleted file mode 100644 index 91fd0a5b..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/app/src/AuditLabel.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { requireNativeViewManager } from 'expo-modules-core' - -// Minimal native view wrapper. Props and events are not yet typed or -// forwarded from the native module definition. -const NativeAuditLabel = requireNativeViewManager('AuditLabel') - -export default NativeAuditLabel diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md deleted file mode 100644 index e6af7ae6..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Build a native iOS label component (AuditLabel) exposed as a React component. It should display text and notify JS when the user interacts with it. \ No newline at end of file diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx deleted file mode 100644 index 6798f6b7..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/App.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import AuditLabel from './src/AuditLabel' - -export default function App() { - return ( - - Audit Label - { - console.log('AuditLabel is ready') - }} - style={styles.label} - /> - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - label: { - height: 44, - width: 200, - }, -}) diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift deleted file mode 100644 index c1fb573f..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelModule.swift +++ /dev/null @@ -1,13 +0,0 @@ -import ExpoModulesCore - -public class AuditLabelModule: Module { - public func definition() -> ModuleDefinition { - Name("AuditLabel") - View(AuditLabelView.self) { - Prop("title") { (view: AuditLabelView, title: String) in - view.label.text = title - } - Events("onReady") - } - } -} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift deleted file mode 100644 index d693c8df..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/ios/AuditLabelView.swift +++ /dev/null @@ -1,25 +0,0 @@ -import ExpoModulesCore - -final class AuditLabelView: ExpoView { - let label = UILabel() - let onReady = EventDispatcher() - - required init(appContext: AppContext? = nil) { - super.init(appContext: appContext) - label.numberOfLines = 0 - addSubview(label) - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) - addGestureRecognizer(tapGesture) - } - - override func layoutSubviews() { - super.layoutSubviews() - label.frame = bounds - } - - @objc - private func handleTap() { - onReady() - } -} diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx deleted file mode 100644 index 7f00d1ad..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/reference/src/AuditLabel.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { requireNativeViewManager } from 'expo-modules-core' -import type { StyleProp, ViewStyle } from 'react-native' - -type Props = { - title: string - onReady?: () => void - style?: StyleProp -} - -export default requireNativeViewManager('AuditLabel') diff --git a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml b/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml deleted file mode 100644 index 22c182c6..00000000 --- a/evals/expo-modules/06-rn-expo-modules-inline-view-events-props/requirements.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/ios/AuditLabelModule.swift - - app/ios/AuditLabelView.swift - - app/src/AuditLabel.tsx -requirements: - - id: view-definition-used - description: "Must define a View(...) in the native module definition." - - id: typed-props - description: "Must declare native view props in native code and in the JS wrapper." - - id: events-declared - description: "Must declare emitted events in the module definition and expose handlers in TS props." - - id: require-native-view-manager - description: "Must use requireNativeViewManager for the React wrapper." diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx deleted file mode 100644 index b6f514f3..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/App.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useEffect, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import { audit, type AuditResult } from './src' - -export default function App() { - const [result, setResult] = useState(null) - - useEffect(() => { - audit().then(setResult) - }, []) - - return ( - - Audit - - Status: {result ? (result.ok ? 'ok' : 'failed') : 'running…'} - - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts deleted file mode 100644 index 620533ae..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/build/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export declare function audit(): Promise diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json deleted file mode 100644 index bb030e50..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/expo-module.config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "platforms": ["apple", "android"], - "apple": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json deleted file mode 100644 index 9fda2c4f..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "expo-audit", - "version": "1.0.0", - "main": "build/index.js", - "types": ".typegen-tmp/index.d.ts", - "files": [ - "src", - "expo-module.config.json" - ], - "scripts": { - "build": "expo-module build", - "typegen": "tsc --emitDeclarationOnly --outDir .typegen-tmp" - }, - "devDependencies": { - "expo-module-scripts": "^4.0.0", - "typescript": "^5.3.0" - } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts deleted file mode 100644 index 4d049abc..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/app/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type AuditResult = { - ok: boolean -} - -export async function audit(): Promise { - return { ok: true } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md deleted file mode 100644 index 468ddb1d..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/prompt.md +++ /dev/null @@ -1 +0,0 @@ -The package exports TypeScript types but consumers report the types are missing after install. Ensure the generated TypeScript declarations are available and exported correctly from the package. \ No newline at end of file diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx deleted file mode 100644 index b6f514f3..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/App.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { useEffect, useState } from 'react' -import { StyleSheet, Text, View } from 'react-native' - -import { audit, type AuditResult } from './src' - -export default function App() { - const [result, setResult] = useState(null) - - useEffect(() => { - audit().then(setResult) - }, []) - - return ( - - Audit - - Status: {result ? (result.ok ? 'ok' : 'failed') : 'running…'} - - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts deleted file mode 100644 index 4b80a156..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/build/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type AuditResult = { - ok: boolean -} -export declare function audit(): Promise diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json deleted file mode 100644 index bb030e50..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/expo-module.config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "platforms": ["apple", "android"], - "apple": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json deleted file mode 100644 index 871fe040..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "expo-audit", - "version": "1.0.0", - "main": "build/index.js", - "types": "build/index.d.ts", - "files": [ - "src", - "build", - "expo-module.config.json" - ], - "scripts": { - "build": "expo-module build", - "typegen": "tsc --emitDeclarationOnly --outDir build" - }, - "devDependencies": { - "expo-module-scripts": "^4.0.0", - "typescript": "^5.3.0" - } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts deleted file mode 100644 index 4d049abc..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/reference/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type AuditResult = { - ok: boolean -} - -export async function audit(): Promise { - return { ok: true } -} diff --git a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml b/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml deleted file mode 100644 index 601aa1cf..00000000 --- a/evals/expo-modules/07-rn-expo-modules-typegen-stable-generated-files/requirements.yaml +++ /dev/null @@ -1,17 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/build/index.d.ts - - app/expo-module.config.json - - app/package.json - - app/src/index.ts -requirements: - - id: expo-module-config-platforms - description: "Must keep expo-module.config.json platforms and module class names explicit." - - id: generated-types-stable-path - description: "Must write generated TypeScript declarations to a stable committed path." - - id: exports-types - description: "Must export the public TypeScript types from the package entrypoint." - - id: no-ephemeral-output-only - description: "Must not rely only on an ignored temp typegen output directory." diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx deleted file mode 100644 index 27b0b48d..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/App.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Audit - - Camera access is required to run a device audit. - - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts deleted file mode 100644 index 9d852b79..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/app.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ExpoConfig } from 'expo/config' - -const config: ExpoConfig = { - name: 'audit', - slug: 'audit', - plugins: [], -} - -export default config diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts deleted file mode 100644 index ab02eb4c..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/app/plugin/withAuditPermissions.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ConfigPlugin } from 'expo/config-plugins' - -export const withAuditPermissions: ConfigPlugin = (config) => { - return config -} - -export default withAuditPermissions diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md deleted file mode 100644 index 7e3e36ca..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/prompt.md +++ /dev/null @@ -1 +0,0 @@ -The app needs camera access on both iOS and Android. Create a local config plugin that ensures the necessary permissions are declared in the native projects during prebuild. \ No newline at end of file diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx deleted file mode 100644 index 27b0b48d..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/App.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Audit - - Camera access is required to run a device audit. - - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts deleted file mode 100644 index b5b5a9da..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/app.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ExpoConfig } from 'expo/config' - -const config: ExpoConfig = { - name: 'audit', - slug: 'audit', - plugins: [ - ['./plugin/withAuditPermissions', { cameraMessage: 'Allow camera access to run a device audit.' }], - ], -} - -export default config diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts deleted file mode 100644 index d45e552f..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/reference/plugin/withAuditPermissions.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { AndroidConfig, ConfigPlugin, withAndroidManifest, withInfoPlist } from 'expo/config-plugins' - -const CAMERA = 'android.permission.CAMERA' - -export const withAuditPermissions: ConfigPlugin<{ cameraMessage: string }> = (config, props) => { - config = withInfoPlist(config, (nextConfig) => { - nextConfig.modResults.NSCameraUsageDescription = props.cameraMessage - return nextConfig - }) - return withAndroidManifest(config, (nextConfig) => { - AndroidConfig.Permissions.addPermission(nextConfig.modResults, CAMERA) - return nextConfig - }) -} - -export default withAuditPermissions diff --git a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml b/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml deleted file mode 100644 index 3bb8e6c9..00000000 --- a/evals/expo-modules/08-rn-expo-modules-config-plugin-permissions/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/app.config.ts - - app/plugin/withAuditPermissions.ts -requirements: - - id: config-plugin-export - description: "Must export a ConfigPlugin from the plugin file." - - id: ios-permission-string - description: "Must write the iOS permission string through withInfoPlist or equivalent config-plugin mod." - - id: android-permission-idempotent - description: "Must add Android permission through AndroidConfig.Permissions helpers or idempotent manifest editing." - - id: plugin-used-in-app-config - description: "Must wire the local config plugin into app.config.ts/app.json." diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx deleted file mode 100644 index fe6a0653..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/App.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import { getPlatform } from './src' - -let platform = 'unknown' - -try { - platform = getPlatform() -} catch { - // No implementation is registered for the current platform. -} - -export default function App() { - return ( - - Audit - Running on: {platform} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json deleted file mode 100644 index bb030e50..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/expo-module.config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "platforms": ["apple", "android"], - "apple": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] } -} diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts deleted file mode 100644 index 1dc8e5c7..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/AuditModule.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export type AuditModule = { - getPlatform(): string -} - -export default requireNativeModule('AuditModule') diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts deleted file mode 100644 index 837598e4..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/app/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import AuditModule from './AuditModule' - -export function getPlatform() { - return AuditModule.getPlatform() -} - -export default AuditModule diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md b/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md deleted file mode 100644 index 0411f60d..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Add a new platform implementation to an Expo module without breaking autolinking config or JS exports. diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx deleted file mode 100644 index fe6a0653..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/App.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -import { getPlatform } from './src' - -let platform = 'unknown' - -try { - platform = getPlatform() -} catch { - // No implementation is registered for the current platform. -} - -export default function App() { - return ( - - Audit - Running on: {platform} - - ) -} - -const styles = StyleSheet.create({ - screen: { - alignItems: 'center', - backgroundColor: '#fff', - flex: 1, - justifyContent: 'center', - padding: 20, - rowGap: 10, - }, - title: { - color: '#111827', - fontSize: 20, - fontWeight: '600', - textAlign: 'center', - }, - subtitle: { - color: '#6b7280', - textAlign: 'center', - }, -}) diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json deleted file mode 100644 index a037d2f3..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/expo-module.config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "platforms": ["apple", "android", "web"], - "apple": { "modules": ["AuditModule"] }, - "android": { "modules": ["expo.modules.audit.AuditModule"] } -} diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts deleted file mode 100644 index 1dc8e5c7..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { requireNativeModule } from 'expo-modules-core' - -export type AuditModule = { - getPlatform(): string -} - -export default requireNativeModule('AuditModule') diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts deleted file mode 100644 index a1a9ba3a..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/AuditModule.web.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { AuditModule } from './AuditModule' - -const AuditModuleWeb: AuditModule = { - getPlatform() { - return 'web' - }, -} - -export default AuditModuleWeb diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts b/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts deleted file mode 100644 index 837598e4..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/reference/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import AuditModule from './AuditModule' - -export function getPlatform() { - return AuditModule.getPlatform() -} - -export default AuditModule diff --git a/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml b/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml deleted file mode 100644 index 3bcc9204..00000000 --- a/evals/expo-modules/10-rn-expo-modules-add-platform-support/requirements.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx - - app/expo-module.config.json - - app/src/AuditModule.ts - - app/src/index.ts -requirements: - - id: platform-added-to-config - description: "Must add web to expo-module.config.json platforms without adding an unsupported web.modules block." - - id: platform-implementation-file - description: "Must include a .web.ts implementation file for the added platform." - - id: js-export-preserved - description: "Must preserve the JS/TS public export surface and route exports through a platform-resolved module file." - - id: autolinking-not-broken - description: "Must not remove existing Apple/iOS or Android native module declarations while adding web." diff --git a/evals/expo-modules/README.md b/evals/expo-modules/README.md deleted file mode 100644 index 3b606126..00000000 --- a/evals/expo-modules/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# Expo Modules eval category - -## category overview - -Expo Modules evals are statically judged file tasks covering inline modules, native module naming, JS wrappers, config plugins, type generation, and module scaffolding. - -## library baseline and naming - -- Baseline: Expo SDK 56 Expo Modules API. -- Inline modules are SDK 56 experimental behavior and are judged from app config plus Kotlin/Swift files. -- Eval IDs start with two digits and the `rn-expo-modules-` prefix. - -## best practices - -### official best-practice sources - -- Expo Modules API overview: https://docs.expo.dev/modules/overview/ -- Expo Modules API reference: https://docs.expo.dev/modules/module-api/ -- Inline modules reference: https://docs.expo.dev/modules/inline-modules-reference/ -- Type generation reference: https://docs.expo.dev/modules/typescript/ -- expo-module.config.json reference: https://docs.expo.dev/modules/module-config/ -- Config plugins introduction: https://docs.expo.dev/config-plugins/introduction/ - -### best-practice inventory - -- M1: Enable inline modules through expo.experiments.inlineModules and valid watchedDirectories. -- M2: Keep inline module file names, class names, and module names aligned. -- M3: Wrap native modules from JS with requireNativeModule or requireNativeViewManager and typed helpers. -- M4: Declare native view props/events in both native module definitions and JS wrappers. -- M5: Keep type generation output stable and committed when it is part of the public surface. -- M6: Write config plugins through Expo config-plugin mods and make permission changes idempotent. diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 5fd81087..3fab5673 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -72,10 +72,9 @@ \section{React Native methodology} \midrule Animation & 13 & React Native animation behavior, including \texttt{Animated} and \texttt{react-native-reanimated}. \\ Asynchronous state & 13 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ -Expo Modules & 10 & Static Expo Modules API tasks covering inline modules, native naming, JS wrappers, type generation, config plugins, and scaffolding. \\ Expo Router & 12 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, data loaders, suspense, and not-found routing. \\ -Expo SDK & 26 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ -Expo UI & 12 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ +Expo SDK & 25 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ +Expo UI & 9 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ Lists & 18 & List rendering, item interactions, virtualization patterns, and sectioned data presentation. \\ Navigation & 13 & Screen transitions, stack/modal flows, route params, and navigation state handling. \\ React Native APIs & 9 & Core platform API usage such as layout, keyboard, accessibility, and device integration primitives. \\ @@ -595,7 +594,7 @@ \section{Conflict of Interest} The authors are affiliated with Callstack. The experiments used commercially available infrastructure acquired and operated independently; no direct sponsorship, funding, or editorial influence was provided for this work. \section{Conclusion} -The current repository state contains \textbf{151} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. +The current repository state contains \textbf{137} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. Two practical implications follow. First, React Native development difficulty is not uniform: models that are competitive on navigation and structural code generation can still be unreliable on behavior-heavy work, where correctness depends on timing, gesture/animation dynamics, and state invalidation semantics. For practitioners, this suggests applying the most scrutiny (and the most automated protection via tests and runtime validation) to animation and async-state code paths, even when a model performs strongly overall. Second, requirement-level evaluation yields actionable signals: per-requirement verdict traces support targeted prompt iteration, scaffolding improvements, and dataset evolution without collapsing all behavior into a single task-level pass/fail. From 6f6f303a17e363fe1ff8cd976842d7a712804cff Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 10:14:35 +0400 Subject: [PATCH 19/32] fix(evals): frame expo-ui conversion prompts as migrations, not builds Evals 01, 02, 11, 12 seed a real React Native screen that the reference converts to Expo UI, so the prompt should describe migrating/converting the existing UI rather than building from scratch. Reword accordingly to match the seeded starting point. Co-Authored-By: Claude Opus 4.6 --- evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md | 2 +- evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md | 2 +- evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md | 2 +- .../12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md index 6ede98f8..139d130f 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md +++ b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md @@ -1 +1 @@ -Build a universal Expo UI screen that renders native UI components alongside React Native content. \ No newline at end of file +Migrate the account screen in App.tsx to Expo UI universal components under a Host, keeping React Native content only where it is intentionally hosted. \ No newline at end of file diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md index 80a9d41c..c27856ae 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md +++ b/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md @@ -1 +1 @@ -Build a settings panel in App.tsx using Expo UI universal layout and control components with controlled state. \ No newline at end of file +Migrate the settings panel in App.tsx from React Native components to Expo UI universal layout and control components, keeping the state controlled. \ No newline at end of file diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md index 02c849fa..61ea0859 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md @@ -1 +1 @@ -Build an Android Jetpack Compose search field in App.tsx using Expo UI whose text value is held in native state instead of React state. \ No newline at end of file +Migrate the search field in App.tsx to an Expo UI Jetpack Compose text field whose value is held in native state instead of React state. \ No newline at end of file diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md index 85667563..c60dae15 100644 --- a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md +++ b/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md @@ -1 +1 @@ -Add platform-specific native styling modifiers to the Expo UI components in App.tsx, supporting both iOS and Android. \ No newline at end of file +Convert the platform-styled card in App.tsx to Expo UI, applying its iOS and Android styling through each platform's native modifiers. \ No newline at end of file From 26bfb55d57fff6dc193e4ec77226c93e92779250 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 10:18:00 +0400 Subject: [PATCH 20/32] refactor(evals): drop redundant expo-ui host-root eval; de-alias Text imports - Remove expo-ui universal-host-root eval (01): overlapped the universal-layout-controls eval on the Host-root concept, which the latter already covers with richer layout/control coverage. Renumber layout-controls to 01 so the category starts cleanly. - Drop the unnecessary `Text as UIText/MaterialText/ComposeText` aliases where no react-native Text is imported; use plain `Text`. Eval 12 keeps its aliases (it imports Text from both platform entrypoints). - Update README and whitepaper counts (expo-ui 9 to 8, suite total 136). Co-Authored-By: Claude Opus 4.6 --- README.md | 4 +- .../app/App.tsx | 49 ------------------- .../prompt.md | 1 - .../reference/App.tsx | 30 ------------ .../requirements.yaml | 13 ----- .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 8 +-- .../requirements.yaml | 0 .../reference/App.tsx | 6 +-- .../reference/App.tsx | 9 +--- paper/benchmark-methodology-whitepaper.tex | 4 +- 12 files changed, 13 insertions(+), 111 deletions(-) delete mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx delete mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md delete mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx delete mode 100644 evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml rename evals/expo-ui/{02-rn-expo-ui-universal-layout-controls => 01-rn-expo-ui-universal-layout-controls}/app/App.tsx (100%) rename evals/expo-ui/{02-rn-expo-ui-universal-layout-controls => 01-rn-expo-ui-universal-layout-controls}/prompt.md (100%) rename evals/expo-ui/{02-rn-expo-ui-universal-layout-controls => 01-rn-expo-ui-universal-layout-controls}/reference/App.tsx (75%) rename evals/expo-ui/{02-rn-expo-ui-universal-layout-controls => 01-rn-expo-ui-universal-layout-controls}/requirements.yaml (100%) diff --git a/README.md b/README.md index 16520015..bd130ce4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A benchmark suite for evaluating how coding models solve real React Native tasks ## Available Evals -Groups map to top-level folders under `evals/`. The current suite contains 137 evals. +Groups map to top-level folders under `evals/`. The current suite contains 136 evals. | Group | Path | Evals | Status | | ----------------- | ------------------------- | ----: | ------ | @@ -12,7 +12,7 @@ Groups map to top-level folders under `evals/`. The current suite contains 137 e | async-state | `evals/async-state` | 13 | Active | | expo-router | `evals/expo-router` | 12 | Active | | expo-sdk | `evals/expo-sdk` | 25 | Active | -| expo-ui | `evals/expo-ui` | 9 | Active | +| expo-ui | `evals/expo-ui` | 8 | Active | | lists | `evals/lists` | 18 | Active | | navigation | `evals/navigation` | 13 | Active | | react-native-apis | `evals/react-native-apis` | 9 | Active | diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx deleted file mode 100644 index df5d8056..00000000 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/app/App.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Account - - Signed in as - jordan@example.com - - Manage your profile and notification settings. - - ) -} - -const styles = StyleSheet.create({ - card: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 12, - borderWidth: 1, - padding: 16, - rowGap: 4, - width: '100%', - }, - hint: { - color: '#6b7280', - }, - label: { - color: '#6b7280', - fontSize: 13, - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 16, - }, - title: { - color: '#111827', - fontSize: 24, - fontWeight: '700', - }, - value: { - color: '#111827', - fontSize: 16, - fontWeight: '600', - }, -}) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md b/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md deleted file mode 100644 index 139d130f..00000000 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Migrate the account screen in App.tsx to Expo UI universal components under a Host, keeping React Native content only where it is intentionally hosted. \ No newline at end of file diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx deleted file mode 100644 index 2bfccec7..00000000 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/reference/App.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Host, RNHostView, Text as UIText } from '@expo/ui' -import { StyleSheet, Text, View } from 'react-native' - -export default function App() { - return ( - - Account - Signed in as - jordan@example.com - - - Manage your profile and notification settings. - - - - ) -} - -const styles = StyleSheet.create({ - hint: { - color: '#6b7280', - }, - hintWrapper: { - paddingTop: 8, - }, - screen: { - flex: 1, - padding: 20, - }, -}) diff --git a/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml b/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml deleted file mode 100644 index 06f9aeda..00000000 --- a/evals/expo-ui/01-rn-expo-ui-universal-host-root/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: imports-universal-host - description: "Must import Host from @expo/ui." - - id: host-root-wraps-native-ui - description: "Must render Expo UI native components inside a Host root." - - id: rn-host-view-only-for-rn-children - description: "Must not use RNHostView unless embedding React Native children inside a native UI subtree." - - id: no-glass-effect - description: "Must not import expo-glass-effect or treat GlassEffect as part of @expo/ui." diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/app/App.tsx similarity index 100% rename from evals/expo-ui/02-rn-expo-ui-universal-layout-controls/app/App.tsx rename to evals/expo-ui/01-rn-expo-ui-universal-layout-controls/app/App.tsx diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/prompt.md similarity index 100% rename from evals/expo-ui/02-rn-expo-ui-universal-layout-controls/prompt.md rename to evals/expo-ui/01-rn-expo-ui-universal-layout-controls/prompt.md diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx similarity index 75% rename from evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx rename to evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx index 769f10a2..bdb53b8c 100644 --- a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/reference/App.tsx +++ b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx @@ -1,4 +1,4 @@ -import { Button, Column, Host, Row, Switch, Text as UIText } from '@expo/ui' +import { Button, Column, Host, Row, Switch, Text } from '@expo/ui' import { useState } from 'react' export default function App() { @@ -13,15 +13,15 @@ export default function App() { return ( - Notifications + Notifications - Push notifications + Push notifications - Email updates + Email updates diff --git a/evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml similarity index 100% rename from evals/expo-ui/02-rn-expo-ui-universal-layout-controls/requirements.yaml rename to evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx index a34d1dce..fa5f6403 100644 --- a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx +++ b/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx @@ -1,4 +1,4 @@ -import { Column, Host, Text as MaterialText, useMaterialColors } from '@expo/ui/jetpack-compose' +import { Column, Host, Text, useMaterialColors } from '@expo/ui/jetpack-compose' export default function App() { const colors = useMaterialColors() @@ -6,9 +6,9 @@ export default function App() { return ( - Today + Today - You have 3 tasks due + You have 3 tasks due diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx index 0377dd38..de28ba3b 100644 --- a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx +++ b/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -1,16 +1,11 @@ -import { - Host, - Text as ComposeText, - TextField, - useNativeState, -} from '@expo/ui/jetpack-compose' +import { Host, Text, TextField, useNativeState } from '@expo/ui/jetpack-compose' export default function App() { const query = useNativeState('') return ( - Search + Search { diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 3fab5673..2a87f3d4 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -74,7 +74,7 @@ \section{React Native methodology} Asynchronous state & 13 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ Expo Router & 12 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, data loaders, suspense, and not-found routing. \\ Expo SDK & 25 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ -Expo UI & 9 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ +Expo UI & 8 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ Lists & 18 & List rendering, item interactions, virtualization patterns, and sectioned data presentation. \\ Navigation & 13 & Screen transitions, stack/modal flows, route params, and navigation state handling. \\ React Native APIs & 9 & Core platform API usage such as layout, keyboard, accessibility, and device integration primitives. \\ @@ -594,7 +594,7 @@ \section{Conflict of Interest} The authors are affiliated with Callstack. The experiments used commercially available infrastructure acquired and operated independently; no direct sponsorship, funding, or editorial influence was provided for this work. \section{Conclusion} -The current repository state contains \textbf{137} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. +The current repository state contains \textbf{136} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. Two practical implications follow. First, React Native development difficulty is not uniform: models that are competitive on navigation and structural code generation can still be unreliable on behavior-heavy work, where correctness depends on timing, gesture/animation dynamics, and state invalidation semantics. For practitioners, this suggests applying the most scrutiny (and the most automated protection via tests and runtime validation) to animation and async-state code paths, even when a model performs strongly overall. Second, requirement-level evaluation yields actionable signals: per-requirement verdict traces support targeted prompt iteration, scaffolding improvements, and dataset evolution without collapsing all behavior into a single task-level pass/fail. From 9efd191668c4239edf071b7ebe6bbc3982fcb6bf Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 10:20:38 +0400 Subject: [PATCH 21/32] chore(evals): renumber expo-sdk and expo-ui sequentially Close the numbering gaps left by removed evals so prefixes run consecutively: expo-sdk is now 01-25 (was missing 11) and expo-ui is now 01-08 (was missing 02/06/07/09). Pure directory renames; eval content, counts, and other categories are unchanged. Pre-existing gaps in animation/async-state/navigation are left as-is since they are referenced by the frozen historical result tables under paper/export. Co-Authored-By: Claude Opus 4.6 --- .../app/App.tsx | 0 .../app/app.config.ts | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../reference/app.config.ts | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../app/app.config.ts | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../reference/app.config.ts | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 92 files changed, 0 insertions(+), 0 deletions(-) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/app/App.tsx (100%) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/app/app.config.ts (100%) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/prompt.md (100%) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/reference/App.tsx (100%) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/reference/app.config.ts (100%) rename evals/expo-sdk/{12-rn-expo-notifications-config-plugin-no-notification-field => 11-rn-expo-notifications-config-plugin-no-notification-field}/requirements.yaml (100%) rename evals/expo-sdk/{13-rn-expo-filesystem-object-api-read-write => 12-rn-expo-filesystem-object-api-read-write}/app/App.tsx (100%) rename evals/expo-sdk/{13-rn-expo-filesystem-object-api-read-write => 12-rn-expo-filesystem-object-api-read-write}/prompt.md (100%) rename evals/expo-sdk/{13-rn-expo-filesystem-object-api-read-write => 12-rn-expo-filesystem-object-api-read-write}/reference/App.tsx (100%) rename evals/expo-sdk/{13-rn-expo-filesystem-object-api-read-write => 12-rn-expo-filesystem-object-api-read-write}/requirements.yaml (100%) rename evals/expo-sdk/{14-rn-expo-filesystem-legacy-root-methods => 13-rn-expo-filesystem-legacy-root-methods}/app/App.tsx (100%) rename evals/expo-sdk/{14-rn-expo-filesystem-legacy-root-methods => 13-rn-expo-filesystem-legacy-root-methods}/prompt.md (100%) rename evals/expo-sdk/{14-rn-expo-filesystem-legacy-root-methods => 13-rn-expo-filesystem-legacy-root-methods}/reference/App.tsx (100%) rename evals/expo-sdk/{14-rn-expo-filesystem-legacy-root-methods => 13-rn-expo-filesystem-legacy-root-methods}/requirements.yaml (100%) rename evals/expo-sdk/{15-rn-expo-filesystem-download-upload => 14-rn-expo-filesystem-download-upload}/app/App.tsx (100%) rename evals/expo-sdk/{15-rn-expo-filesystem-download-upload => 14-rn-expo-filesystem-download-upload}/prompt.md (100%) rename evals/expo-sdk/{15-rn-expo-filesystem-download-upload => 14-rn-expo-filesystem-download-upload}/reference/App.tsx (100%) rename evals/expo-sdk/{15-rn-expo-filesystem-download-upload => 14-rn-expo-filesystem-download-upload}/requirements.yaml (100%) rename evals/expo-sdk/{16-rn-expo-media-library-granular-writeonly => 15-rn-expo-media-library-granular-writeonly}/app/App.tsx (100%) rename evals/expo-sdk/{16-rn-expo-media-library-granular-writeonly => 15-rn-expo-media-library-granular-writeonly}/prompt.md (100%) rename evals/expo-sdk/{16-rn-expo-media-library-granular-writeonly => 15-rn-expo-media-library-granular-writeonly}/reference/App.tsx (100%) rename evals/expo-sdk/{16-rn-expo-media-library-granular-writeonly => 15-rn-expo-media-library-granular-writeonly}/requirements.yaml (100%) rename evals/expo-sdk/{17-rn-expo-media-library-file-asset-create => 16-rn-expo-media-library-file-asset-create}/app/App.tsx (100%) rename evals/expo-sdk/{17-rn-expo-media-library-file-asset-create => 16-rn-expo-media-library-file-asset-create}/prompt.md (100%) rename evals/expo-sdk/{17-rn-expo-media-library-file-asset-create => 16-rn-expo-media-library-file-asset-create}/reference/App.tsx (100%) rename evals/expo-sdk/{17-rn-expo-media-library-file-asset-create => 16-rn-expo-media-library-file-asset-create}/requirements.yaml (100%) rename evals/expo-sdk/{18-rn-expo-calendar-dev-build-permissions => 17-rn-expo-calendar-dev-build-permissions}/app/App.tsx (100%) rename evals/expo-sdk/{18-rn-expo-calendar-dev-build-permissions => 17-rn-expo-calendar-dev-build-permissions}/prompt.md (100%) rename evals/expo-sdk/{18-rn-expo-calendar-dev-build-permissions => 17-rn-expo-calendar-dev-build-permissions}/reference/App.tsx (100%) rename evals/expo-sdk/{18-rn-expo-calendar-dev-build-permissions => 17-rn-expo-calendar-dev-build-permissions}/requirements.yaml (100%) rename evals/expo-sdk/{19-rn-expo-contacts-config-fields-query => 18-rn-expo-contacts-config-fields-query}/app/App.tsx (100%) rename evals/expo-sdk/{19-rn-expo-contacts-config-fields-query => 18-rn-expo-contacts-config-fields-query}/prompt.md (100%) rename evals/expo-sdk/{19-rn-expo-contacts-config-fields-query => 18-rn-expo-contacts-config-fields-query}/reference/App.tsx (100%) rename evals/expo-sdk/{19-rn-expo-contacts-config-fields-query => 18-rn-expo-contacts-config-fields-query}/requirements.yaml (100%) rename evals/expo-sdk/{20-rn-expo-audio-player-lifecycle => 19-rn-expo-audio-player-lifecycle}/app/App.tsx (100%) rename evals/expo-sdk/{20-rn-expo-audio-player-lifecycle => 19-rn-expo-audio-player-lifecycle}/prompt.md (100%) rename evals/expo-sdk/{20-rn-expo-audio-player-lifecycle => 19-rn-expo-audio-player-lifecycle}/reference/App.tsx (100%) rename evals/expo-sdk/{20-rn-expo-audio-player-lifecycle => 19-rn-expo-audio-player-lifecycle}/requirements.yaml (100%) rename evals/expo-sdk/{21-rn-expo-video-player-view => 20-rn-expo-video-player-view}/app/App.tsx (100%) rename evals/expo-sdk/{21-rn-expo-video-player-view => 20-rn-expo-video-player-view}/prompt.md (100%) rename evals/expo-sdk/{21-rn-expo-video-player-view => 20-rn-expo-video-player-view}/reference/App.tsx (100%) rename evals/expo-sdk/{21-rn-expo-video-player-view => 20-rn-expo-video-player-view}/requirements.yaml (100%) rename evals/expo-sdk/{22-rn-expo-video-thumbnails-replacement => 21-rn-expo-video-thumbnails-replacement}/app/App.tsx (100%) rename evals/expo-sdk/{22-rn-expo-video-thumbnails-replacement => 21-rn-expo-video-thumbnails-replacement}/prompt.md (100%) rename evals/expo-sdk/{22-rn-expo-video-thumbnails-replacement => 21-rn-expo-video-thumbnails-replacement}/reference/App.tsx (100%) rename evals/expo-sdk/{22-rn-expo-video-thumbnails-replacement => 21-rn-expo-video-thumbnails-replacement}/requirements.yaml (100%) rename evals/expo-sdk/{23-rn-expo-updates-download-progress-reload-screen => 22-rn-expo-updates-download-progress-reload-screen}/app/App.tsx (100%) rename evals/expo-sdk/{23-rn-expo-updates-download-progress-reload-screen => 22-rn-expo-updates-download-progress-reload-screen}/prompt.md (100%) rename evals/expo-sdk/{23-rn-expo-updates-download-progress-reload-screen => 22-rn-expo-updates-download-progress-reload-screen}/reference/App.tsx (100%) rename evals/expo-sdk/{23-rn-expo-updates-download-progress-reload-screen => 22-rn-expo-updates-download-progress-reload-screen}/requirements.yaml (100%) rename evals/expo-sdk/{24-rn-expo-updates-request-header-override => 23-rn-expo-updates-request-header-override}/app/App.tsx (100%) rename evals/expo-sdk/{24-rn-expo-updates-request-header-override => 23-rn-expo-updates-request-header-override}/prompt.md (100%) rename evals/expo-sdk/{24-rn-expo-updates-request-header-override => 23-rn-expo-updates-request-header-override}/reference/App.tsx (100%) rename evals/expo-sdk/{24-rn-expo-updates-request-header-override => 23-rn-expo-updates-request-header-override}/requirements.yaml (100%) rename evals/expo-sdk/{25-rn-expo-status-navigation-bar-current-api => 24-rn-expo-status-navigation-bar-current-api}/app/App.tsx (100%) rename evals/expo-sdk/{25-rn-expo-status-navigation-bar-current-api => 24-rn-expo-status-navigation-bar-current-api}/prompt.md (100%) rename evals/expo-sdk/{25-rn-expo-status-navigation-bar-current-api => 24-rn-expo-status-navigation-bar-current-api}/reference/App.tsx (100%) rename evals/expo-sdk/{25-rn-expo-status-navigation-bar-current-api => 24-rn-expo-status-navigation-bar-current-api}/requirements.yaml (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/app/App.tsx (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/app/app.config.ts (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/prompt.md (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/reference/App.tsx (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/reference/app.config.ts (100%) rename evals/expo-sdk/{26-rn-expo-build-properties-precompiled-headers => 25-rn-expo-build-properties-precompiled-headers}/requirements.yaml (100%) rename evals/expo-ui/{03-rn-expo-ui-bottom-sheet-controlled => 02-rn-expo-ui-bottom-sheet-controlled}/app/App.tsx (100%) rename evals/expo-ui/{03-rn-expo-ui-bottom-sheet-controlled => 02-rn-expo-ui-bottom-sheet-controlled}/prompt.md (100%) rename evals/expo-ui/{03-rn-expo-ui-bottom-sheet-controlled => 02-rn-expo-ui-bottom-sheet-controlled}/reference/App.tsx (100%) rename evals/expo-ui/{03-rn-expo-ui-bottom-sheet-controlled => 02-rn-expo-ui-bottom-sheet-controlled}/requirements.yaml (100%) rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-no-android-open => 03-rn-expo-ui-datetimepicker-no-android-open}/app/App.tsx (100%) rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-no-android-open => 03-rn-expo-ui-datetimepicker-no-android-open}/prompt.md (100%) rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-no-android-open => 03-rn-expo-ui-datetimepicker-no-android-open}/reference/App.tsx (100%) rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-no-android-open => 03-rn-expo-ui-datetimepicker-no-android-open}/requirements.yaml (100%) rename evals/expo-ui/{05-rn-expo-ui-datetimepicker-unsupported-props => 04-rn-expo-ui-datetimepicker-unsupported-props}/app/App.tsx (100%) rename evals/expo-ui/{05-rn-expo-ui-datetimepicker-unsupported-props => 04-rn-expo-ui-datetimepicker-unsupported-props}/prompt.md (100%) rename evals/expo-ui/{05-rn-expo-ui-datetimepicker-unsupported-props => 04-rn-expo-ui-datetimepicker-unsupported-props}/reference/App.tsx (100%) rename evals/expo-ui/{05-rn-expo-ui-datetimepicker-unsupported-props => 04-rn-expo-ui-datetimepicker-unsupported-props}/requirements.yaml (100%) rename evals/expo-ui/{08-rn-expo-ui-pagerview-drop-in => 05-rn-expo-ui-pagerview-drop-in}/app/App.tsx (100%) rename evals/expo-ui/{08-rn-expo-ui-pagerview-drop-in => 05-rn-expo-ui-pagerview-drop-in}/prompt.md (100%) rename evals/expo-ui/{08-rn-expo-ui-pagerview-drop-in => 05-rn-expo-ui-pagerview-drop-in}/reference/App.tsx (100%) rename evals/expo-ui/{08-rn-expo-ui-pagerview-drop-in => 05-rn-expo-ui-pagerview-drop-in}/requirements.yaml (100%) rename evals/expo-ui/{10-rn-expo-ui-material-colors-symbols => 06-rn-expo-ui-material-colors-symbols}/app/App.tsx (100%) rename evals/expo-ui/{10-rn-expo-ui-material-colors-symbols => 06-rn-expo-ui-material-colors-symbols}/prompt.md (100%) rename evals/expo-ui/{10-rn-expo-ui-material-colors-symbols => 06-rn-expo-ui-material-colors-symbols}/reference/App.tsx (100%) rename evals/expo-ui/{10-rn-expo-ui-material-colors-symbols => 06-rn-expo-ui-material-colors-symbols}/requirements.yaml (100%) rename evals/expo-ui/{11-rn-expo-ui-native-state-text-input => 07-rn-expo-ui-native-state-text-input}/app/App.tsx (100%) rename evals/expo-ui/{11-rn-expo-ui-native-state-text-input => 07-rn-expo-ui-native-state-text-input}/prompt.md (100%) rename evals/expo-ui/{11-rn-expo-ui-native-state-text-input => 07-rn-expo-ui-native-state-text-input}/reference/App.tsx (100%) rename evals/expo-ui/{11-rn-expo-ui-native-state-text-input => 07-rn-expo-ui-native-state-text-input}/requirements.yaml (100%) rename evals/expo-ui/{12-rn-expo-ui-platform-modifier-escape-hatch => 08-rn-expo-ui-platform-modifier-escape-hatch}/app/App.tsx (100%) rename evals/expo-ui/{12-rn-expo-ui-platform-modifier-escape-hatch => 08-rn-expo-ui-platform-modifier-escape-hatch}/prompt.md (100%) rename evals/expo-ui/{12-rn-expo-ui-platform-modifier-escape-hatch => 08-rn-expo-ui-platform-modifier-escape-hatch}/reference/App.tsx (100%) rename evals/expo-ui/{12-rn-expo-ui-platform-modifier-escape-hatch => 08-rn-expo-ui-platform-modifier-escape-hatch}/requirements.yaml (100%) diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/App.tsx diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/prompt.md similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/prompt.md rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/prompt.md diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/app.config.ts diff --git a/evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml similarity index 100% rename from evals/expo-sdk/12-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml rename to evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/app/App.tsx similarity index 100% rename from evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/app/App.tsx rename to evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/app/App.tsx diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md similarity index 100% rename from evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/prompt.md rename to evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx similarity index 100% rename from evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/reference/App.tsx rename to evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx diff --git a/evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml similarity index 100% rename from evals/expo-sdk/13-rn-expo-filesystem-object-api-read-write/requirements.yaml rename to evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx similarity index 100% rename from evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/app/App.tsx rename to evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md similarity index 100% rename from evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/prompt.md rename to evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx similarity index 100% rename from evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/reference/App.tsx rename to evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx diff --git a/evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml similarity index 100% rename from evals/expo-sdk/14-rn-expo-filesystem-legacy-root-methods/requirements.yaml rename to evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/app/App.tsx similarity index 100% rename from evals/expo-sdk/15-rn-expo-filesystem-download-upload/app/App.tsx rename to evals/expo-sdk/14-rn-expo-filesystem-download-upload/app/App.tsx diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md similarity index 100% rename from evals/expo-sdk/15-rn-expo-filesystem-download-upload/prompt.md rename to evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx similarity index 100% rename from evals/expo-sdk/15-rn-expo-filesystem-download-upload/reference/App.tsx rename to evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx diff --git a/evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml similarity index 100% rename from evals/expo-sdk/15-rn-expo-filesystem-download-upload/requirements.yaml rename to evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/app/App.tsx similarity index 100% rename from evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/app/App.tsx rename to evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/app/App.tsx diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md similarity index 100% rename from evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/prompt.md rename to evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx similarity index 100% rename from evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/reference/App.tsx rename to evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx diff --git a/evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml similarity index 100% rename from evals/expo-sdk/16-rn-expo-media-library-granular-writeonly/requirements.yaml rename to evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/app/App.tsx similarity index 100% rename from evals/expo-sdk/17-rn-expo-media-library-file-asset-create/app/App.tsx rename to evals/expo-sdk/16-rn-expo-media-library-file-asset-create/app/App.tsx diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md similarity index 100% rename from evals/expo-sdk/17-rn-expo-media-library-file-asset-create/prompt.md rename to evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx similarity index 100% rename from evals/expo-sdk/17-rn-expo-media-library-file-asset-create/reference/App.tsx rename to evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx diff --git a/evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/requirements.yaml similarity index 100% rename from evals/expo-sdk/17-rn-expo-media-library-file-asset-create/requirements.yaml rename to evals/expo-sdk/16-rn-expo-media-library-file-asset-create/requirements.yaml diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/app/App.tsx similarity index 100% rename from evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/app/App.tsx rename to evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/app/App.tsx diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md similarity index 100% rename from evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/prompt.md rename to evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx similarity index 100% rename from evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/reference/App.tsx rename to evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx diff --git a/evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml similarity index 100% rename from evals/expo-sdk/18-rn-expo-calendar-dev-build-permissions/requirements.yaml rename to evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/app/App.tsx similarity index 100% rename from evals/expo-sdk/19-rn-expo-contacts-config-fields-query/app/App.tsx rename to evals/expo-sdk/18-rn-expo-contacts-config-fields-query/app/App.tsx diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md similarity index 100% rename from evals/expo-sdk/19-rn-expo-contacts-config-fields-query/prompt.md rename to evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx similarity index 100% rename from evals/expo-sdk/19-rn-expo-contacts-config-fields-query/reference/App.tsx rename to evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx diff --git a/evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml similarity index 100% rename from evals/expo-sdk/19-rn-expo-contacts-config-fields-query/requirements.yaml rename to evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/app/App.tsx similarity index 100% rename from evals/expo-sdk/20-rn-expo-audio-player-lifecycle/app/App.tsx rename to evals/expo-sdk/19-rn-expo-audio-player-lifecycle/app/App.tsx diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md similarity index 100% rename from evals/expo-sdk/20-rn-expo-audio-player-lifecycle/prompt.md rename to evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx similarity index 100% rename from evals/expo-sdk/20-rn-expo-audio-player-lifecycle/reference/App.tsx rename to evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx diff --git a/evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml similarity index 100% rename from evals/expo-sdk/20-rn-expo-audio-player-lifecycle/requirements.yaml rename to evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx b/evals/expo-sdk/20-rn-expo-video-player-view/app/App.tsx similarity index 100% rename from evals/expo-sdk/21-rn-expo-video-player-view/app/App.tsx rename to evals/expo-sdk/20-rn-expo-video-player-view/app/App.tsx diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/prompt.md b/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md similarity index 100% rename from evals/expo-sdk/21-rn-expo-video-player-view/prompt.md rename to evals/expo-sdk/20-rn-expo-video-player-view/prompt.md diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx b/evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx similarity index 100% rename from evals/expo-sdk/21-rn-expo-video-player-view/reference/App.tsx rename to evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx diff --git a/evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml b/evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml similarity index 100% rename from evals/expo-sdk/21-rn-expo-video-player-view/requirements.yaml rename to evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/app/App.tsx similarity index 100% rename from evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/app/App.tsx rename to evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/app/App.tsx diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md similarity index 100% rename from evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/prompt.md rename to evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/reference/App.tsx similarity index 100% rename from evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/reference/App.tsx rename to evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/reference/App.tsx diff --git a/evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml similarity index 100% rename from evals/expo-sdk/22-rn-expo-video-thumbnails-replacement/requirements.yaml rename to evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/app/App.tsx similarity index 100% rename from evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/app/App.tsx rename to evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/app/App.tsx diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md similarity index 100% rename from evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/prompt.md rename to evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx similarity index 100% rename from evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/reference/App.tsx rename to evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx diff --git a/evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml similarity index 100% rename from evals/expo-sdk/23-rn-expo-updates-download-progress-reload-screen/requirements.yaml rename to evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx b/evals/expo-sdk/23-rn-expo-updates-request-header-override/app/App.tsx similarity index 100% rename from evals/expo-sdk/24-rn-expo-updates-request-header-override/app/App.tsx rename to evals/expo-sdk/23-rn-expo-updates-request-header-override/app/App.tsx diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md b/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md similarity index 100% rename from evals/expo-sdk/24-rn-expo-updates-request-header-override/prompt.md rename to evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx b/evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/App.tsx similarity index 100% rename from evals/expo-sdk/24-rn-expo-updates-request-header-override/reference/App.tsx rename to evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/App.tsx diff --git a/evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml similarity index 100% rename from evals/expo-sdk/24-rn-expo-updates-request-header-override/requirements.yaml rename to evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/app/App.tsx similarity index 100% rename from evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/app/App.tsx rename to evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/app/App.tsx diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md similarity index 100% rename from evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/prompt.md rename to evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx similarity index 100% rename from evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/reference/App.tsx rename to evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx diff --git a/evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/requirements.yaml similarity index 100% rename from evals/expo-sdk/25-rn-expo-status-navigation-bar-current-api/requirements.yaml rename to evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/requirements.yaml diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/app/App.tsx similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/App.tsx rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/app/App.tsx diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/app/app.config.ts similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/app/app.config.ts rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/app/app.config.ts diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/prompt.md rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/reference/App.tsx similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/App.tsx rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/reference/App.tsx diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/reference/app.config.ts similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/reference/app.config.ts rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/reference/app.config.ts diff --git a/evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml similarity index 100% rename from evals/expo-sdk/26-rn-expo-build-properties-precompiled-headers/requirements.yaml rename to evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/app/App.tsx similarity index 100% rename from evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/app/App.tsx rename to evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/app/App.tsx diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md similarity index 100% rename from evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/prompt.md rename to evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx similarity index 100% rename from evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx rename to evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/reference/App.tsx diff --git a/evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml similarity index 100% rename from evals/expo-ui/03-rn-expo-ui-bottom-sheet-controlled/requirements.yaml rename to evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/prompt.md rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx rename to evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/prompt.md rename to evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx rename to evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx diff --git a/evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml rename to evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx b/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/app/App.tsx similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/app/App.tsx rename to evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/app/App.tsx diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md b/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/prompt.md similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/prompt.md rename to evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/prompt.md diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx b/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/reference/App.tsx similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/reference/App.tsx rename to evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/reference/App.tsx diff --git a/evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml b/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/requirements.yaml similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-pagerview-drop-in/requirements.yaml rename to evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/requirements.yaml diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx b/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/app/App.tsx similarity index 100% rename from evals/expo-ui/10-rn-expo-ui-material-colors-symbols/app/App.tsx rename to evals/expo-ui/06-rn-expo-ui-material-colors-symbols/app/App.tsx diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md b/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/prompt.md similarity index 100% rename from evals/expo-ui/10-rn-expo-ui-material-colors-symbols/prompt.md rename to evals/expo-ui/06-rn-expo-ui-material-colors-symbols/prompt.md diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/reference/App.tsx similarity index 100% rename from evals/expo-ui/10-rn-expo-ui-material-colors-symbols/reference/App.tsx rename to evals/expo-ui/06-rn-expo-ui-material-colors-symbols/reference/App.tsx diff --git a/evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml b/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/requirements.yaml similarity index 100% rename from evals/expo-ui/10-rn-expo-ui-material-colors-symbols/requirements.yaml rename to evals/expo-ui/06-rn-expo-ui-material-colors-symbols/requirements.yaml diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx b/evals/expo-ui/07-rn-expo-ui-native-state-text-input/app/App.tsx similarity index 100% rename from evals/expo-ui/11-rn-expo-ui-native-state-text-input/app/App.tsx rename to evals/expo-ui/07-rn-expo-ui-native-state-text-input/app/App.tsx diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/07-rn-expo-ui-native-state-text-input/prompt.md similarity index 100% rename from evals/expo-ui/11-rn-expo-ui-native-state-text-input/prompt.md rename to evals/expo-ui/07-rn-expo-ui-native-state-text-input/prompt.md diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-native-state-text-input/reference/App.tsx similarity index 100% rename from evals/expo-ui/11-rn-expo-ui-native-state-text-input/reference/App.tsx rename to evals/expo-ui/07-rn-expo-ui-native-state-text-input/reference/App.tsx diff --git a/evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/07-rn-expo-ui-native-state-text-input/requirements.yaml similarity index 100% rename from evals/expo-ui/11-rn-expo-ui-native-state-text-input/requirements.yaml rename to evals/expo-ui/07-rn-expo-ui-native-state-text-input/requirements.yaml diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx b/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx similarity index 100% rename from evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx rename to evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md b/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/prompt.md similarity index 100% rename from evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/prompt.md rename to evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/prompt.md diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx similarity index 100% rename from evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx rename to evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx diff --git a/evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml b/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml similarity index 100% rename from evals/expo-ui/12-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml rename to evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml From 827992d2a787a6863ceb95704764145553ea5f34 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 13:31:25 +0400 Subject: [PATCH 22/32] fix(evals): make expo-router/01 a real SDK 56 import migration The eval previously called useNavigation() and discarded the result (dead code that only existed to satisfy a requirement) and dropped the ThemeProvider entirely in the reference, which is a lossy migration that never demonstrated the actual SDK 56 change. Per the SDK 55->56 migration docs, app code must move @react-navigation imports to expo-router entry points: theming to expo-router/react-navigation and createNativeStackNavigator to the file-based Stack. Rework the eval to show exactly that: scaffold is a themed native-stack layout; reference migrates ThemeProvider/DefaultTheme to expo-router/react-navigation and the navigator to expo-router Stack, keeping the theme wrapper. Replace the contrived useNavigation requirement with a theming-import migration one. Co-Authored-By: Claude Opus 4.6 --- .../app/_layout.tsx | 4 +--- .../reference/_layout.tsx | 12 +++++++----- .../requirements.yaml | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx index 59f398e3..0031e553 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx @@ -1,11 +1,9 @@ -import { DefaultTheme, ThemeProvider, useNavigation } from '@react-navigation/native' +import { DefaultTheme, ThemeProvider } from '@react-navigation/native' import { createNativeStackNavigator } from '@react-navigation/native-stack' const Stack = createNativeStackNavigator() export default function Layout() { - useNavigation() - return ( diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx index 51570c06..5690fe1b 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx @@ -1,10 +1,12 @@ -import { Stack, useNavigation } from 'expo-router' +import { Stack } from 'expo-router' +import { DefaultTheme, ThemeProvider } from 'expo-router/react-navigation' export default function Layout() { - useNavigation() return ( - - - + + + + + ) } diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml index c3b72eb8..b9d0d4fb 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml @@ -10,5 +10,5 @@ requirements: description: "Must not import from @react-navigation/native or @react-navigation/native-stack in app route files." - id: keeps-file-system-layout description: "Must keep navigation defined through Expo Router layout and route files." - - id: uses-sdk56-exported-hooks - description: "Must use SDK 56-compatible exports such as useNavigation from expo-router." + - id: migrates-theme-import-to-expo-router + description: "Must import React Navigation theming such as ThemeProvider and DefaultTheme from expo-router/react-navigation, and keep wrapping the Stack in it, rather than dropping it or importing from @react-navigation/native." From 490b35a6380cd9d25095ac297a0ee974067388d9 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 14:47:16 +0400 Subject: [PATCH 23/32] fix(evals): address PR review on expo-router evals Apply reviewer guidance across the expo-router category: - 02: simplify scaffold to a single Products screen (no prescribed routing); prompt now requires adding a navigating button that passes the product id; requirements verify the param is passed, read via the hook, and rendered on the details screen - 03: prompt specifies the header (title, back-button label, right button that alerts); requirement checks the alert handler instead of a vague "deterministic handler" - 04: drop the iOS-only framing; reword as adding a collapsing large title - 05: reframe as converting the existing stack layout to native tabs - 06: prompt specifies exact SF Symbols (house/house.fill) and badge (2); requirements check those props - 07: require Stack.Protected (base is a Stack); prompt says add gating to existing routes; drop the dead handleSignIn stub - 09 (data-loaders-config): dropped per review - 10 (static/server loader): prompt is explicit about what to move/fetch - 11 (suspense): drop the unexplained internal must-not; require a visible Loading indicator - 12 (not-found): prompt/requirements explicit about the message, home link, and scoping the catch-all - Renumber expo-router to 01-11 after dropping 09; update README/whitepaper counts (expo-router 12->11, suite total 135) Co-Authored-By: Claude Opus 4.6 --- README.md | 4 ++-- .../app/index.tsx | 6 +++--- .../prompt.md | 2 +- .../reference/index.tsx | 6 ++++-- .../requirements.yaml | 15 +++++++++----- .../app/index.tsx | 2 -- .../prompt.md | 2 +- .../requirements.yaml | 10 +++++----- .../prompt.md | 2 +- .../requirements.yaml | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../requirements.yaml | 12 ++++++----- .../app/sign-in.tsx | 2 -- .../prompt.md | 2 +- .../requirements.yaml | 4 ++-- .../app/app.json | 8 -------- .../app/index.tsx | 20 ------------------- .../prompt.md | 1 - .../reference/app.json | 17 ---------------- .../reference/index.tsx | 11 ---------- .../requirements.yaml | 15 -------------- .../app/_layout.tsx | 0 .../app/index.tsx | 0 .../app/profile.tsx | 0 .../app/server/profile.server.ts | 0 .../prompt.md | 1 + .../reference/_layout.tsx | 0 .../reference/index.tsx | 0 .../reference/profile.tsx | 0 .../reference/server/profile.server.ts | 0 .../requirements.yaml | 0 .../prompt.md | 1 - .../app/_layout.tsx | 0 .../app/index.tsx | 0 .../prompt.md | 1 + .../reference}/_layout.tsx | 0 .../reference/index.tsx | 0 .../requirements.yaml | 14 +++++++++++++ .../app/+not-found.tsx | 0 .../app/[...slug].tsx | 0 .../app}/_layout.tsx | 0 .../app/index.tsx | 0 .../prompt.md | 1 + .../reference/+not-found.tsx | 0 .../reference/_layout.tsx | 0 .../reference/docs/[...slug].tsx | 0 .../reference/index.tsx | 0 .../requirements.yaml | 14 +++++++++++++ .../prompt.md | 1 - .../requirements.yaml | 14 ------------- .../app/_layout.tsx | 5 ----- .../prompt.md | 1 - .../reference/_layout.tsx | 2 -- .../requirements.yaml | 16 --------------- paper/benchmark-methodology-whitepaper.tex | 4 ++-- 56 files changed, 73 insertions(+), 149 deletions(-) delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx delete mode 100644 evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml rename evals/expo-router/{09-rn-expo-router-data-loaders-config => 09-rn-expo-router-static-vs-server-loader}/app/_layout.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/app/index.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/app/profile.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/app/server/profile.server.ts (100%) create mode 100644 evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md rename evals/expo-router/{09-rn-expo-router-data-loaders-config => 09-rn-expo-router-static-vs-server-loader}/reference/_layout.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/reference/index.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/reference/profile.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/reference/server/profile.server.ts (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 09-rn-expo-router-static-vs-server-loader}/requirements.yaml (100%) delete mode 100644 evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 10-rn-expo-router-suspense-fallback-layout}/app/_layout.tsx (100%) rename evals/expo-router/{11-rn-expo-router-suspense-fallback-layout => 10-rn-expo-router-suspense-fallback-layout}/app/index.tsx (100%) create mode 100644 evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md rename evals/expo-router/{11-rn-expo-router-suspense-fallback-layout/app => 10-rn-expo-router-suspense-fallback-layout/reference}/_layout.tsx (100%) rename evals/expo-router/{11-rn-expo-router-suspense-fallback-layout => 10-rn-expo-router-suspense-fallback-layout}/reference/index.tsx (100%) create mode 100644 evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/app/+not-found.tsx (100%) rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/app/[...slug].tsx (100%) rename evals/expo-router/{11-rn-expo-router-suspense-fallback-layout/reference => 11-rn-expo-router-not-found-route-priority/app}/_layout.tsx (100%) rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/app/index.tsx (100%) create mode 100644 evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/reference/+not-found.tsx (100%) rename evals/expo-router/{10-rn-expo-router-static-vs-server-loader => 11-rn-expo-router-not-found-route-priority}/reference/_layout.tsx (100%) rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/reference/docs/[...slug].tsx (100%) rename evals/expo-router/{12-rn-expo-router-not-found-route-priority => 11-rn-expo-router-not-found-route-priority}/reference/index.tsx (100%) create mode 100644 evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml delete mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md delete mode 100644 evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml delete mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx delete mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md delete mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx delete mode 100644 evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml diff --git a/README.md b/README.md index bd130ce4..0c385f65 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ A benchmark suite for evaluating how coding models solve real React Native tasks ## Available Evals -Groups map to top-level folders under `evals/`. The current suite contains 136 evals. +Groups map to top-level folders under `evals/`. The current suite contains 135 evals. | Group | Path | Evals | Status | | ----------------- | ------------------------- | ----: | ------ | | animation | `evals/animation` | 13 | Active | | async-state | `evals/async-state` | 13 | Active | -| expo-router | `evals/expo-router` | 12 | Active | +| expo-router | `evals/expo-router` | 11 | Active | | expo-sdk | `evals/expo-sdk` | 25 | Active | | expo-ui | `evals/expo-ui` | 8 | Active | | lists | `evals/lists` | 18 | Active | diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx index 194b87ed..692633b4 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/app/index.tsx @@ -1,11 +1,11 @@ -import { Link } from 'expo-router' import { StyleSheet, Text, View } from 'react-native' +const PRODUCT = { id: '42', name: 'Aurora Headphones' } + export default function Index() { return ( - Products - View details + {PRODUCT.name} ) } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md index 9b2099aa..ec5d09d5 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/prompt.md @@ -1 +1 @@ -Implement a stack layout in an Expo Router app with a main and details screen. \ No newline at end of file +Set up a stack layout and add a Details screen. On the Products screen, add a button that navigates to Details and passes the product id as a route parameter. The Details screen must read that id from the route and render it. \ No newline at end of file diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx index 194b87ed..5f9191b9 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/reference/index.tsx @@ -1,11 +1,13 @@ import { Link } from 'expo-router' import { StyleSheet, Text, View } from 'react-native' +const PRODUCT = { id: '42', name: 'Aurora Headphones' } + export default function Index() { return ( - Products - View details + {PRODUCT.name} + View details ) } diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml index eed21c81..84174091 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml @@ -3,10 +3,15 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/details.tsx requirements: - id: uses-expo-router-stack - description: "Must render Stack from expo-router in _layout.tsx." - - id: no-create-native-stack-navigator - description: "Must not call createNativeStackNavigator or NavigationContainer in Expo Router app code." - - id: registers-screens-by-name - description: "Must configure Stack.Screen entries by file-route names." + description: "Must render Stack from expo-router in _layout.tsx and not call createNativeStackNavigator or NavigationContainer." + - id: navigates-to-details + description: "Must navigate from the Products screen to the details route using expo-router Link or router navigation." + - id: passes-id-param + description: "Must pass the product id as a route parameter when navigating to details." + - id: details-reads-id-with-hook + description: "The details screen must read the id from the route with useLocalSearchParams or useGlobalSearchParams." + - id: details-renders-id + description: "The details screen must render the received id value." diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx index 64e1d950..a5bf2cf3 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx @@ -1,8 +1,6 @@ import { StyleSheet, Text, View } from 'react-native' export default function Index() { - const handleCreate = () => {} - return ( Inbox diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md index 87719a81..0b14ca46 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md @@ -1 +1 @@ -Add a back button and title to a screen header in an Expo Router app. \ No newline at end of file +Configure the Inbox screen header in the Stack layout: set the title, a back button label, and a right-side header button that shows an alert when pressed. \ No newline at end of file diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml index f62eb04e..54495fbd 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml @@ -5,10 +5,10 @@ inputs: - app/index.tsx requirements: - id: uses-stack-screen-options-for-header - description: "Must compose header actions via Stack.Screen options (headerRight/headerLeft), not Stack.Toolbar." - - id: route-options-in-layout - description: "Must keep screen options in Expo Router Stack layout/screen configuration." - - id: action-callback-defined - description: "Must wire header action callbacks to deterministic handlers." + description: "Must configure the header via Stack.Screen options (title/headerRight), not Stack.Toolbar." + - id: header-right-shows-alert + description: "The headerRight must render a pressable button whose press handler calls Alert.alert." + - id: sets-title-and-back-button + description: "Must set the screen title and a back button label via headerBackTitle in the Stack.Screen options." - id: no-react-navigation-header-imports description: "Must not import React Navigation header components or types directly." diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md index d799063a..d4578cb2 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/prompt.md @@ -1 +1 @@ -Build an iOS screen with a large collapsing title that collapses on scroll. \ No newline at end of file +Add a large title to the Activity screen that starts large and collapses as the list scrolls. \ No newline at end of file diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml index 4a23e0b4..5979ecc8 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml @@ -9,6 +9,6 @@ requirements: - id: scroll-view-first-child description: "Must make the page content start with a ScrollView or compatible scrollable child." - id: content-inset-adjustment - description: "Must configure automatic content inset behavior for iOS large titles." + description: "Must set contentInsetAdjustmentBehavior to automatic on the scrollable so the large title collapses correctly." - id: stack-only description: "Must use Expo Router Stack, not a manually created native stack." diff --git a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md index 96b93fe0..34001bfc 100644 --- a/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md +++ b/evals/expo-router/05-rn-expo-router-native-tabs-trigger-api/prompt.md @@ -1 +1 @@ -Build a bottom tab layout using Expo Router's native tabs API. \ No newline at end of file +Convert the stack layout in _layout.tsx to Expo Router's native bottom tabs, keeping the Home and Settings routes as tabs. \ No newline at end of file diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md index 2c9ec4f2..39a96917 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/prompt.md @@ -1 +1 @@ -Configure native tab icons, labels, and badges with selected and default states. \ No newline at end of file +In the native tabs layout, give the Home tab an SF Symbol icon that is "house" by default and "house.fill" when selected, and add a badge showing "2" on the Settings tab. \ No newline at end of file diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml index ef527f4a..a7484665 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml @@ -5,11 +5,13 @@ inputs: - app/index.tsx - app/settings.tsx requirements: - - id: selected-default-icon-state - description: "Must configure selected/default icon or label state through NativeTabs.Trigger children." - - id: badge-or-label-child-api - description: "Must use NativeTabs.Trigger.Label/Icon/Badge child APIs for per-tab presentation." + - id: home-icon-default-and-selected + description: "The Home trigger must render NativeTabs.Trigger.Icon with sf set to a default symbol \"house\" and a selected symbol \"house.fill\"." + - id: settings-badge-value + description: "The Settings trigger must render NativeTabs.Trigger.Badge with the value 2." + - id: uses-trigger-child-apis + description: "Must configure per-tab presentation through NativeTabs.Trigger.Icon/Badge/Label child components." - id: route-name-alignment - description: "Must align tab trigger names with file routes." + description: "Must align tab trigger names with the file routes (index, settings)." - id: no-generic-tabs-api description: "Must not use generic Expo Router Tabs for this native-tabs task." diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx index 61725131..d85c982d 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/app/sign-in.tsx @@ -1,8 +1,6 @@ import { StyleSheet, Text, View } from 'react-native' export default function SignIn() { - const handleSignIn = () => {} - return ( Sign in diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md index b61cbe4e..194cf9f4 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/prompt.md @@ -1 +1 @@ -Implement authentication-gated routes in an Expo Router app with a signed-out fallback. \ No newline at end of file +Add authentication gating to the existing Stack routes so the account screen is only reachable when signed in and the sign-in screen only when signed out, using the app's signedIn flag. \ No newline at end of file diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml index 66e66844..a2163165 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -6,8 +6,8 @@ inputs: - app/account.tsx - app/sign-in.tsx requirements: - - id: uses-protected-routes - description: "Must use Stack.Protected, Tabs.Protected, or the Expo Router protected route API." + - id: uses-stack-protected + description: "Must gate routes with Stack.Protected, since the app uses a Stack layout." - id: signed-out-fallback description: "Must provide a deterministic signed-out fallback route." - id: guard-boolean-explicit diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json deleted file mode 100644 index d5f9f747..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/app.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "expo": { - "plugins": ["expo-router"], - "web": { - "bundler": "metro" - } - } -} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx deleted file mode 100644 index 575c1c3d..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/index.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useEffect, useState } from 'react' -import { Text, View } from 'react-native' - -async function fetchGreeting() { - return { greeting: 'Loaded on the route boundary' } -} - -export default function Index() { - const [data, setData] = useState<{ greeting: string } | null>(null) - - useEffect(() => { - fetchGreeting().then(setData) - }, []) - - return ( - - {data?.greeting ?? 'Loading...'} - - ) -} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md b/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md deleted file mode 100644 index 42a5e755..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Enable pre-render data fetching for a route in an Expo Router web app. \ No newline at end of file diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json deleted file mode 100644 index cd134733..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/app.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "expo": { - "plugins": [ - [ - "expo-router", - { - "unstable_useServerDataLoaders": true, - "unstable_useServerRendering": true - } - ] - ], - "web": { - "bundler": "metro", - "output": "server" - } - } -} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx b/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx deleted file mode 100644 index 5d646699..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { useLoaderData } from 'expo-router' -import { Text } from 'react-native' - -export async function loader() { - return { greeting: 'Loaded on the route boundary' } -} - -export default function Index() { - const data = useLoaderData() - return {data.greeting} -} diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml b/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml deleted file mode 100644 index 74ba153c..00000000 --- a/evals/expo-router/09-rn-expo-router-data-loaders-config/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/app.json - - app/_layout.tsx - - app/index.tsx -requirements: - - id: loader-exported-from-route - description: "Must export a loader from the route module." - - id: uses-use-loader-data - description: "Must read loader results with useLoaderData typed to the loader." - - id: router-plugin-configured - description: "Must configure the expo-router plugin with unstable_useServerDataLoaders, unstable_useServerRendering, and web output set to server." - - id: no-client-fetch-duplication - description: "Must not duplicate the same data fetch in a client mount effect." diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/_layout.tsx similarity index 100% rename from evals/expo-router/09-rn-expo-router-data-loaders-config/app/_layout.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/_layout.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/index.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/index.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/index.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/profile.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/profile.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/profile.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md new file mode 100644 index 00000000..368c25b7 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md @@ -0,0 +1 @@ +The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into the server-only module and expose it through a route loader that returns the profile name, then render the name in the client with useLoaderData so the secret never ships in the client bundle. \ No newline at end of file diff --git a/evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx similarity index 100% rename from evals/expo-router/09-rn-expo-router-data-loaders-config/reference/_layout.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/index.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/profile.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/requirements.yaml rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md deleted file mode 100644 index 8d8db8ee..00000000 --- a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Fetch data in an Expo Router web route while keeping server secrets out of the client bundle. \ No newline at end of file diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/app/_layout.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/app/_layout.tsx rename to evals/expo-router/10-rn-expo-router-suspense-fallback-layout/app/_layout.tsx diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/app/index.tsx similarity index 100% rename from evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/index.tsx rename to evals/expo-router/10-rn-expo-router-suspense-fallback-layout/app/index.tsx diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md new file mode 100644 index 00000000..ff85e686 --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md @@ -0,0 +1 @@ +The index route renders async content with React Suspense. Add a route-level SuspenseFallback that shows a "Loading…" indicator until the content resolves. \ No newline at end of file diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx similarity index 100% rename from evals/expo-router/11-rn-expo-router-suspense-fallback-layout/app/_layout.tsx rename to evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx similarity index 100% rename from evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/index.tsx rename to evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml new file mode 100644 index 00000000..66fe860b --- /dev/null +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx +requirements: + - id: uses-suspense-fallback + description: "Must export a route-level SuspenseFallback function from the route module." + - id: fallback-renders-loading-indicator + description: "SuspenseFallback must render a visible loading indicator (for example a Text reading \"Loading…\") while the async route content is pending." + - id: default-export-renders-async-content + description: "Must keep the route's default export rendering the resolved async content." + - id: no-global-loading-hack + description: "Must not replace the route content with a permanent loading screen that never shows the resolved content." diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/app/+not-found.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/app/[...slug].tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/_layout.tsx similarity index 100% rename from evals/expo-router/11-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/app/_layout.tsx diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/index.tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/app/index.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/app/index.tsx diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md b/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md new file mode 100644 index 00000000..18d8cbd4 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md @@ -0,0 +1 @@ +Implement a +not-found screen that shows a clear "this screen does not exist" message and a link back to the home screen, and scope the docs catch-all route so it does not shadow the not-found route for unknown paths. \ No newline at end of file diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/+not-found.tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/+not-found.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/+not-found.tsx diff --git a/evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx similarity index 100% rename from evals/expo-router/10-rn-expo-router-static-vs-server-loader/reference/_layout.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/docs/[...slug].tsx diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/index.tsx similarity index 100% rename from evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/index.tsx rename to evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/index.tsx diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml b/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml new file mode 100644 index 00000000..9add2a85 --- /dev/null +++ b/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml @@ -0,0 +1,14 @@ +version: 1 +inputs: + files: + - app/_layout.tsx + - app/index.tsx + - app/+not-found.tsx + - app/[...slug].tsx +requirements: + - id: plus-not-found-route + description: "Must implement +not-found.tsx as the not-found route." + - id: not-found-message-and-home-link + description: "The +not-found screen must render a clear not-found message and a Link to the home route \"/\"." + - id: catch-all-scoped-not-shadowing + description: "Must scope the catch-all route (for example under docs/) so unknown paths fall through to +not-found instead of being caught by the catch-all." diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md deleted file mode 100644 index c2514a3a..00000000 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Add a loading fallback for async route content in an Expo Router layout. \ No newline at end of file diff --git a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml b/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml deleted file mode 100644 index 037136f6..00000000 --- a/evals/expo-router/11-rn-expo-router-suspense-fallback-layout/requirements.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: 1 -inputs: - files: - - app/_layout.tsx - - app/index.tsx -requirements: - - id: uses-suspense-fallback - description: "Must export a route-level SuspenseFallback function and must not render expo-router's internal SuspenseFallback component directly." - - id: fallback-has-deterministic-ui - description: "Must render a deterministic fallback UI while async route content is pending." - - id: stack-remains-rendered - description: "Must still render the nested Stack/Slot route outlet." - - id: no-global-loading-hack - description: "Must not replace the route outlet with a permanent loading screen." diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx deleted file mode 100644 index 99996670..00000000 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/app/_layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { Stack } from 'expo-router' - -export default function Layout() { - return -} diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md b/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md deleted file mode 100644 index 236c696f..00000000 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Handle unknown routes gracefully and give users a way back to known content. \ No newline at end of file diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx b/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx deleted file mode 100644 index 61625f48..00000000 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/reference/_layout.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import { Stack } from 'expo-router' -export default function Layout() { return } diff --git a/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml b/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml deleted file mode 100644 index 7507ce54..00000000 --- a/evals/expo-router/12-rn-expo-router-not-found-route-priority/requirements.yaml +++ /dev/null @@ -1,16 +0,0 @@ -version: 1 -inputs: - files: - - app/_layout.tsx - - app/index.tsx - - app/+not-found.tsx - - app/[...slug].tsx -requirements: - - id: plus-not-found-route - description: "Must implement +not-found.tsx as the not-found route." - - id: uses-unmatched-or-home-link - description: "Must render Unmatched or equivalent missing-route context plus a link back home." - - id: catch-all-does-not-shadow-not-found - description: "Must not rely only on a catch-all route for unknown routes." - - id: deterministic-not-found-copy - description: "Must render deterministic not-found UI." diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 2a87f3d4..031ab701 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -72,7 +72,7 @@ \section{React Native methodology} \midrule Animation & 13 & React Native animation behavior, including \texttt{Animated} and \texttt{react-native-reanimated}. \\ Asynchronous state & 13 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ -Expo Router & 12 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, data loaders, suspense, and not-found routing. \\ +Expo Router & 11 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, static/server loaders, suspense, and not-found routing. \\ Expo SDK & 25 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ Expo UI & 8 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ Lists & 18 & List rendering, item interactions, virtualization patterns, and sectioned data presentation. \\ @@ -594,7 +594,7 @@ \section{Conflict of Interest} The authors are affiliated with Callstack. The experiments used commercially available infrastructure acquired and operated independently; no direct sponsorship, funding, or editorial influence was provided for this work. \section{Conclusion} -The current repository state contains \textbf{136} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. +The current repository state contains \textbf{135} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. Two practical implications follow. First, React Native development difficulty is not uniform: models that are competitive on navigation and structural code generation can still be unreliable on behavior-heavy work, where correctness depends on timing, gesture/animation dynamics, and state invalidation semantics. For practitioners, this suggests applying the most scrutiny (and the most automated protection via tests and runtime validation) to animation and async-state code paths, even when a model performs strongly overall. Second, requirement-level evaluation yields actionable signals: per-requirement verdict traces support targeted prompt iteration, scaffolding improvements, and dataset evolution without collapsing all behavior into a single task-level pass/fail. From 9717bc633a8bc693c0a1eb92eaa72148185f7e37 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 15:20:02 +0400 Subject: [PATCH 24/32] fix(evals): apply PR-review guidelines to expo-sdk and expo-ui Carry the expo-router review principles across the remaining Expo evals: - Prompt explicitness: replace vague "handle appropriately/gracefully/ correctly" with the concrete behavior the requirements check (which permission flow, which states, what to fetch, which channel/album, etc.) - Framing: reword build/implement/create to "wire up" since each scaffold already seeds the screen and a stubbed handler - Requirement fixes: - expo-sdk/13: drop the unjudgeable "make the code path clear enough" requirement (already covered by the no-root-legacy-import check) - expo-sdk/23: drop the un-prompted no-hardcoded-secrets requirement - expo-ui/01: drop the un-prompted no-glass-effect requirement - expo-ui/04: tighten the two vague requirements (supported props only; a visible text fallback for an unavailable mode) to checkable form - expo-sdk/01 (author edit), 02, 03 and expo-ui/02 already carried explicit prompts + tightened requirements; references verified against every updated requirement Co-Authored-By: Claude Opus 4.6 --- .../01-rn-expo-camera-permission-denied-retry/prompt.md | 2 +- .../expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md | 2 +- .../02-rn-expo-camera-active-unmount-focus/requirements.yaml | 2 +- .../expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md | 2 +- .../03-rn-expo-camera-barcode-audio-config/requirements.yaml | 2 +- .../04-rn-expo-image-picker-canceled-assets-guard/prompt.md | 2 +- .../05-rn-expo-image-picker-video-permission-nuance/prompt.md | 2 +- .../06-rn-expo-location-foreground-geocode-guard/prompt.md | 2 +- .../07-rn-expo-location-background-foreground-first/prompt.md | 2 +- .../08-rn-expo-location-accuracy-authorization/prompt.md | 2 +- .../09-rn-expo-notifications-android-channel-token/prompt.md | 2 +- .../10-rn-expo-notifications-listener-cleanup/prompt.md | 2 +- .../12-rn-expo-filesystem-object-api-read-write/prompt.md | 2 +- .../requirements.yaml | 2 -- .../expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md | 2 +- .../15-rn-expo-media-library-granular-writeonly/prompt.md | 2 +- .../16-rn-expo-media-library-file-asset-create/prompt.md | 2 +- .../17-rn-expo-calendar-dev-build-permissions/prompt.md | 2 +- .../18-rn-expo-contacts-config-fields-query/prompt.md | 2 +- evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md | 2 +- evals/expo-sdk/20-rn-expo-video-player-view/prompt.md | 2 +- .../prompt.md | 2 +- .../23-rn-expo-updates-request-header-override/prompt.md | 2 +- .../requirements.yaml | 4 +--- .../24-rn-expo-status-navigation-bar-current-api/prompt.md | 2 +- .../01-rn-expo-ui-universal-layout-controls/requirements.yaml | 2 -- evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md | 2 +- .../02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml | 4 ++-- .../requirements.yaml | 4 ++-- 29 files changed, 29 insertions(+), 35 deletions(-) diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md index 8206eff4..524f9da1 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md @@ -1 +1 @@ -Build a production-ready camera entry flow with expo-camera that handles all permission states, including denial and the user returning from system settings. \ No newline at end of file +Wire this camera screen up to expo-camera. Request camera permission only when the user taps "Enable Camera" (never on mount), and guard against overlapping prompts while a request is already in flight. Render CameraView in the preview area only once permission is granted, and keep the "Camera is off" fallback for every other state. When permission is permanently blocked (denied with canAskAgain false), show the Settings recovery block and open the system settings with Linking.openSettings() instead of prompting again. Re-check the permission whenever the app returns to the foreground so a grant made in Settings is picked up. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md index eff17bda..68bd5c89 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md @@ -1 +1 @@ -Build a camera preview screen that handles being backgrounded, switching away, or manually disabled. The camera should work correctly when the user returns to the screen. \ No newline at end of file +Convert this preview screen to use a real expo-camera CameraView. Drive CameraView's active prop from a combination of the app being in the foreground (listen to AppState and set it false whenever the app leaves the active state) and the existing "Camera enabled" switch, so backgrounding the app or flipping the switch pauses the preview without tearing down permission state. When camera permission is not granted, do not render CameraView at all — show the paused/fallback text instead. Remove the AppState listener when the component unmounts. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml index 24d3ab5f..a6c54ea2 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml @@ -4,7 +4,7 @@ inputs: - app/App.tsx requirements: - id: camera-active-derived-from-visibility - description: "Must pass CameraView an active prop derived from foreground/focus state and user-enabled preview state." + description: "Must pass CameraView an active prop derived from AppState foreground state and the user-enabled preview switch." - id: camera-appstate-background-pauses description: "Must listen to AppState and set active false when the app leaves the active state." - id: camera-view-unmounted-without-permission diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md index 38cd7bb9..d48ac355 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md @@ -1 +1 @@ -Build a camera screen that scans barcodes and optionally records video with audio. Handle permissions appropriately and use current expo-camera APIs. \ No newline at end of file +Convert this scanner screen to a real expo-camera CameraView once camera permission is granted. Configure barcode scanning through the CameraView's barcodeScannerSettings with an explicit barcodeTypes allowlist of "qr" and "ean13" (not every type), and in the onBarcodeScanned handler ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml index 98bd6085..1f9ec3c0 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml @@ -6,7 +6,7 @@ requirements: - id: uses-camera-view-barcode-settings description: "Must use CameraView with barcodeScannerSettings and onBarcodeScanned instead of the deprecated BarCodeScanner package/API." - id: limits-barcode-types - description: "Must configure a deterministic barcodeTypes allowlist instead of accepting every type implicitly." + description: "Must configure an explicit barcodeTypes allowlist containing qr and ean13 instead of accepting every type implicitly." - id: deduplicates-scan-results description: "Must debounce or deduplicate repeated barcode scan events before updating state." - id: microphone-request-on-video-intent diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md index d65046c9..66d26ba2 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md @@ -1 +1 @@ -Implement an image picker flow that lets the user select an image from their library and displays it. Handle all outcomes of the picker gracefully. \ No newline at end of file +Wire up the Choose from Library button to expo-image-picker. Launch the picker only from the button, show the selected image in the preview, and keep a stable empty state when the user cancels. Read the current result shape (result.canceled and result.assets) and current mediaTypes so a cancel never crashes. diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md index 2e17a2ac..e2d7748a 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md @@ -1 +1 @@ -Build a video-library picker that lets the user select a video from their library. Handle all permission states and picker outcomes correctly. \ No newline at end of file +Wire up the Choose Video button to a video-library picker. Check media-library permission before launching (from the button, not on mount), render a distinct state for denied or limited access, select videos only, and display the chosen video after validating it is a video. diff --git a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md index c2934bb5..4a07ff29 100644 --- a/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md +++ b/evals/expo-sdk/06-rn-expo-location-foreground-geocode-guard/prompt.md @@ -1 +1 @@ -Implement a foreground location flow that requests permission on demand, retrieves the user's current location, and reverse-geocodes it to a human-readable address. \ No newline at end of file +Wire up the Find My Location button: request foreground location permission on press, get the current position with an explicit accuracy, and reverse-geocode it to a human-readable address — falling back gracefully when no address is returned. diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md index e1603a3d..8239b3f6 100644 --- a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md @@ -1 +1 @@ -Create a screen that lets the user opt into background location tracking. Use expo-location and TaskManager to receive location updates when the app is in the background. \ No newline at end of file +Wire up the Track in background switch. When turned on, request foreground location permission first and then background permission, and start background location updates only after both are granted; when turned off, stop the updates. Define the TaskManager task once and avoid starting duplicate updates. diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md index 99dd9a1c..71872b98 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/prompt.md @@ -1 +1 @@ -Build a foreground-location status panel that shows the user's current location permission state and accuracy level. Handle all the ways permission and accuracy can differ across platforms. \ No newline at end of file +Wire up the location status panel to show the current permission state and whether access is precise or approximate, inspecting the platform accuracy details. Do not assume a granted permission means precise location, render an approximate-access explanation, and offer to open Settings when permission is permanently blocked. diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md index a3901222..588a3200 100644 --- a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md @@ -1 +1 @@ -Implement push-notification registration using expo-notifications. The app should obtain an Expo push token and be ready to receive notifications on both platforms. \ No newline at end of file +Wire up the Register button to obtain an Expo push token with expo-notifications. On Android, create the notification channel before requesting the token; gate the request behind granted notification permission; pass the EAS projectId; and render a deterministic error state if registration fails. diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md index 11d9d445..383c9af4 100644 --- a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/prompt.md @@ -1 +1 @@ -Create a notification inbox component that displays notifications received while the app is in the foreground and tracks when the user taps a notification. \ No newline at end of file +Wire up the notification inbox: subscribe to notifications received while the app is foregrounded and to the user tapping a notification, updating the list from both. Register the listeners on mount and remove each subscription on unmount. diff --git a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md index e4f8cee8..bbc74635 100644 --- a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md +++ b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md @@ -1 +1 @@ -Implement a simple notes feature that persists text to a cache file using expo-file-system. The app should handle first-run (no existing file) gracefully. \ No newline at end of file +Wire up the notes screen's save and load using the expo-file-system object API (File/Directory/Paths). Persist the text to a cache file, create the directory idempotently, and on first run (no file yet) load fallback text instead of crashing. diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml index 3befc401..405f0a20 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml @@ -9,7 +9,5 @@ requirements: description: "Must import old helper methods from expo-file-system/legacy when retaining the legacy method style." - id: object-api-preferred description: "Must use File/Directory/Paths from expo-file-system for new read/write code." - - id: documents-runtime-throw-trap - description: "Must make the code path clear enough that root legacy methods are avoided because they throw at runtime in current SDKs." - id: keeps-uri-boundary-explicit description: "Must keep file URI/path construction explicit instead of concatenating undefined documentDirectory/cacheDirectory root constants." diff --git a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md index 679d97f6..8661fdbd 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md +++ b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md @@ -1 +1 @@ -Implement a flow that downloads a remote file to local storage and then uploads it to a server endpoint. Use expo-file-system and show download progress. \ No newline at end of file +Wire up the sync flow: download the remote file into a local cache directory while showing download progress, then upload it to the server endpoint. Use the expo-file-system object API for the download and a web-compatible upload (fetch/FormData), and render a deterministic failure state on error. diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md index b17c17ea..1c5a6cf1 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md @@ -1 +1 @@ -Create a feature that saves a generated image to the user's photo library. The app only needs to save photos, not browse existing ones. Handle permissions appropriately on both platforms. \ No newline at end of file +Wire up the Save button to save the generated image to the photo library. Request write-only permission (the app never browses existing photos), do not read the library, and render a deterministic state when permission is denied. diff --git a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md index f40458dd..dd9d3731 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md +++ b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md @@ -1 +1 @@ -Implement a feature that saves a locally generated image to the user's media library and organizes it into an album. Use current expo-media-library APIs. \ No newline at end of file +Wire up the Save button to save the generated image to the media library and add it to an album, using the current expo-media-library class APIs (Asset/Album). Check permission and confirm the file exists before creating the asset. diff --git a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md index bb8c053a..0a582efb 100644 --- a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md +++ b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/prompt.md @@ -1 +1 @@ -Build a screen that lets the user create a calendar event. Use expo-calendar to list available calendars, pick one, and create the event. Handle permission denial gracefully. \ No newline at end of file +Wire up the new-event form to expo-calendar: list the available calendars, let the user pick a writable one, and create the event on it. Handle permission denial with a deterministic fallback. diff --git a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md index 54fcf409..83a9f516 100644 --- a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md +++ b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/prompt.md @@ -1 +1 @@ -Build a contacts lookup screen that displays the user's contacts with names, emails, and photos. Handle permission denial and empty contact lists. \ No newline at end of file +Wire up the Load contacts button to display the user's contacts with their name, emails, and photo. Request permission only when the button is pressed (not on mount), query only the fields shown, and render a deterministic empty state when there are no contacts or permission is denied. diff --git a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md index f1e319b5..2bc57937 100644 --- a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md +++ b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md @@ -1 +1 @@ -Build an audio preview component that plays a sound file, shows playback status, and handles app lifecycle correctly (backgrounding, unmount). Use current Expo audio APIs. \ No newline at end of file +Wire up the audio preview to play a sound file and show its playback status using the current Expo audio APIs (expo-audio, not expo-av). Configure the audio mode deliberately, and pause playback when the app is backgrounded or the component unmounts. diff --git a/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md b/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md index 5fdfc88f..243f5da6 100644 --- a/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md +++ b/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md @@ -1 +1 @@ -Build a video player component that plays a video URL, supports looping and mute controls, and handles visibility changes properly. Use current Expo video APIs. \ No newline at end of file +Wire up the video player to play a video URL with looping and mute controls using the current Expo video APIs (expo-video, not expo-av). Pause or avoid autoplay when the app is backgrounded or the view is not visible. diff --git a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md index 6d7d5c3c..9c7a5fc6 100644 --- a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md +++ b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/prompt.md @@ -1 +1 @@ -Create a screen that checks for OTA updates, shows download progress, and applies the update when ready. Use expo-updates and handle errors and the case where no update is available. \ No newline at end of file +Wire up the updates screen: check for an OTA update, show download progress while it downloads, and apply it with a reload once ready. Handle download errors and the case where no update is available, and do not rely on code running after the reload. diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md b/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md index 8e5c8197..c8a42aef 100644 --- a/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md @@ -1 +1 @@ -Implement a UI that lets users switch between release channels (e.g., production, staging, beta) and check for updates from the selected channel. Use expo-updates. \ No newline at end of file +Wire up the release-channel switcher (production, staging, beta): override the expo-updates request headers for the selected channel and check for an update from it, and reset the override back to default. Show which channel is currently active. diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml index 7f5bed62..5fb748a3 100644 --- a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml @@ -7,9 +7,7 @@ requirements: description: "Must call Updates.setUpdateRequestHeadersOverride with a record or null." - id: clear-override-path description: "Must provide a default path that calls setUpdateRequestHeadersOverride(null)." - - id: no-secret-header-values - description: "Must not hardcode secrets or authorization tokens in update request headers." - id: check-after-header-change description: "Must trigger or expose an update check/fetch flow after changing headers." - id: visible-selected-cohort - description: "Must render the active cohort/header selection so behavior is auditable." + description: "Must render the active channel/header selection so behavior is auditable." diff --git a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md index f8375809..e1153db7 100644 --- a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md +++ b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md @@ -1 +1 @@ -Build a screen that controls the system status bar and navigation bar appearance and optionally applies a glass/blur effect when the platform supports it. Clean up properly on unmount. \ No newline at end of file +Wire up the appearance screen's controls to set the system status bar and navigation bar style, and to toggle a Liquid Glass surface when the platform supports it. Guard Android-only navigation bar calls, remove any visibility listener on cleanup, and restore the default bars on unmount. diff --git a/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml index 795f3d47..c332c9bf 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml +++ b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/requirements.yaml @@ -9,5 +9,3 @@ requirements: description: "Must keep Switch value controlled by React state." - id: host-provides-root description: "Must render controls under Host." - - id: no-glass-effect - description: "Must not import expo-glass-effect or treat GlassEffect as part of @expo/ui." diff --git a/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md index b5a537f8..45cf7fd4 100644 --- a/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md +++ b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/prompt.md @@ -1 +1 @@ -Migrate the bottom sheet in App.tsx to use the Expo UI equivalent with controlled open and close behavior. \ No newline at end of file +Migrate the bottom sheet in App.tsx to the Expo UI community bottom sheet. Keep the ref-driven control that opens the sheet, and add a control inside the sheet that closes it. \ No newline at end of file diff --git a/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml index 62a0b12e..29e6edcb 100644 --- a/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml +++ b/evals/expo-ui/02-rn-expo-ui-bottom-sheet-controlled/requirements.yaml @@ -5,8 +5,8 @@ inputs: requirements: - id: community-bottom-sheet-import description: "Must import BottomSheet APIs from @expo/ui/community/bottom-sheet." - - id: controlled-present-dismiss - description: "Must expose controlled present/dismiss behavior through a ref or state." + - id: controlled-open-and-close + description: "Must drive the sheet through the ref, both opening it (e.g. expand) and closing it (e.g. close) from a control." - id: uses-bottom-sheet-view description: "Must place sheet content in BottomSheetView or documented sheet child wrappers." - id: no-gorhom-import diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml index 21b8bedc..eb5fac4c 100644 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml +++ b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: supported-props-only - description: "Must avoid unsupported community DateTimePicker props from legacy packages." + description: "Must configure the picker using only props supported by @expo/ui/community/datetime-picker (such as value/onValueChange and its display/mode options), not props specific to @react-native-community/datetimepicker." - id: uses-onchange-or-onvaluechange description: "Must handle date changes through onChange or onValueChange." - id: fallback-for-platform-differences - description: "Must render fallback copy for unsupported picker modes/platform behavior." + description: "Must render a visible text fallback for a date/time mode that is not available on the current platform." - id: no-react-native-community-datetimepicker-import description: "Must not import @react-native-community/datetimepicker directly." From f92eda2edf8f0d05d93bc45c3f4c699fe5380b34 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Wed, 1 Jul 2026 15:30:39 +0400 Subject: [PATCH 25/32] refactor(evals): merge the two expo-ui datetimepicker evals into one The no-android-open and unsupported-props evals tested different traps on the same @expo/ui/community/datetime-picker component with the same scaffold pattern. Merge them into a single cross-platform date+time eval that covers every trap: community import, no DateTimePickerAndroid.open, no @react-native-community import, controlled value via onValueChange, undefined-cancel guard, and a platform fallback for an unavailable mode. Adopt the date+time appointment scaffold/reference; renumber expo-ui to 01-07; update README/whitepaper counts (expo-ui 7, suite total 134). Co-Authored-By: Claude Opus 4.6 --- README.md | 4 +- .../app/App.tsx | 0 .../prompt.md | 1 + .../reference/App.tsx | 0 .../requirements.yaml | 17 +++++ .../app/App.tsx | 64 ----------------- .../prompt.md | 1 - .../reference/App.tsx | 70 ------------------- .../requirements.yaml | 13 ---- .../prompt.md | 1 - .../requirements.yaml | 13 ---- .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 0 .../requirements.yaml | 0 paper/benchmark-methodology-whitepaper.tex | 4 +- 28 files changed, 22 insertions(+), 166 deletions(-) rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-unsupported-props => 03-rn-expo-ui-datetimepicker-cross-platform}/app/App.tsx (100%) create mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md rename evals/expo-ui/{04-rn-expo-ui-datetimepicker-unsupported-props => 03-rn-expo-ui-datetimepicker-cross-platform}/reference/App.tsx (100%) create mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml delete mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx delete mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md delete mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx delete mode 100644 evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml delete mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md delete mode 100644 evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml rename evals/expo-ui/{05-rn-expo-ui-pagerview-drop-in => 04-rn-expo-ui-pagerview-drop-in}/app/App.tsx (100%) rename evals/expo-ui/{05-rn-expo-ui-pagerview-drop-in => 04-rn-expo-ui-pagerview-drop-in}/prompt.md (100%) rename evals/expo-ui/{05-rn-expo-ui-pagerview-drop-in => 04-rn-expo-ui-pagerview-drop-in}/reference/App.tsx (100%) rename evals/expo-ui/{05-rn-expo-ui-pagerview-drop-in => 04-rn-expo-ui-pagerview-drop-in}/requirements.yaml (100%) rename evals/expo-ui/{06-rn-expo-ui-material-colors-symbols => 05-rn-expo-ui-material-colors-symbols}/app/App.tsx (100%) rename evals/expo-ui/{06-rn-expo-ui-material-colors-symbols => 05-rn-expo-ui-material-colors-symbols}/prompt.md (100%) rename evals/expo-ui/{06-rn-expo-ui-material-colors-symbols => 05-rn-expo-ui-material-colors-symbols}/reference/App.tsx (100%) rename evals/expo-ui/{06-rn-expo-ui-material-colors-symbols => 05-rn-expo-ui-material-colors-symbols}/requirements.yaml (100%) rename evals/expo-ui/{07-rn-expo-ui-native-state-text-input => 06-rn-expo-ui-native-state-text-input}/app/App.tsx (100%) rename evals/expo-ui/{07-rn-expo-ui-native-state-text-input => 06-rn-expo-ui-native-state-text-input}/prompt.md (100%) rename evals/expo-ui/{07-rn-expo-ui-native-state-text-input => 06-rn-expo-ui-native-state-text-input}/reference/App.tsx (100%) rename evals/expo-ui/{07-rn-expo-ui-native-state-text-input => 06-rn-expo-ui-native-state-text-input}/requirements.yaml (100%) rename evals/expo-ui/{08-rn-expo-ui-platform-modifier-escape-hatch => 07-rn-expo-ui-platform-modifier-escape-hatch}/app/App.tsx (100%) rename evals/expo-ui/{08-rn-expo-ui-platform-modifier-escape-hatch => 07-rn-expo-ui-platform-modifier-escape-hatch}/prompt.md (100%) rename evals/expo-ui/{08-rn-expo-ui-platform-modifier-escape-hatch => 07-rn-expo-ui-platform-modifier-escape-hatch}/reference/App.tsx (100%) rename evals/expo-ui/{08-rn-expo-ui-platform-modifier-escape-hatch => 07-rn-expo-ui-platform-modifier-escape-hatch}/requirements.yaml (100%) diff --git a/README.md b/README.md index 0c385f65..d4f5b3d3 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A benchmark suite for evaluating how coding models solve real React Native tasks ## Available Evals -Groups map to top-level folders under `evals/`. The current suite contains 135 evals. +Groups map to top-level folders under `evals/`. The current suite contains 134 evals. | Group | Path | Evals | Status | | ----------------- | ------------------------- | ----: | ------ | @@ -12,7 +12,7 @@ Groups map to top-level folders under `evals/`. The current suite contains 135 e | async-state | `evals/async-state` | 13 | Active | | expo-router | `evals/expo-router` | 11 | Active | | expo-sdk | `evals/expo-sdk` | 25 | Active | -| expo-ui | `evals/expo-ui` | 8 | Active | +| expo-ui | `evals/expo-ui` | 7 | Active | | lists | `evals/lists` | 18 | Active | | navigation | `evals/navigation` | 13 | Active | | react-native-apis | `evals/react-native-apis` | 9 | Active | diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/app/App.tsx similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/app/App.tsx rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/app/App.tsx diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md new file mode 100644 index 00000000..0367f193 --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md @@ -0,0 +1 @@ +Add cross-platform date and time selection to the appointment form using Expo UI's date/time picker. Keep the selected value in controlled state via onValueChange, guard against an undefined value when the user cancels, and render a text fallback for any date/time mode not available on the current platform. diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx similarity index 100% rename from evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/reference/App.tsx rename to evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml new file mode 100644 index 00000000..21687144 --- /dev/null +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml @@ -0,0 +1,17 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: community-datetime-import + description: "Must import DateTimePicker from @expo/ui/community/datetime-picker." + - id: no-android-open-api + description: "Must not use DateTimePickerAndroid.open." + - id: no-react-native-community-datetimepicker-import + description: "Must not import @react-native-community/datetimepicker directly." + - id: controlled-value-via-onvaluechange + description: "Must keep the selected date/time in controlled state and update it through onValueChange." + - id: handles-undefined-value + description: "Must guard against the onValueChange value being undefined when the user cancels." + - id: platform-mode-fallback + description: "Must render a visible text fallback for a date/time mode not available on the current platform." diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx deleted file mode 100644 index 018c3ec4..00000000 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/app/App.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { useState } from 'react' -import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' - -export default function App() { - const [name, setName] = useState('') - const [date, setDate] = useState(new Date()) - - const handlePickDate = () => {} - - return ( - - New reservation - - - Guest name - - - - - Date - - {date.toDateString()} - - - - ) -} - -const styles = StyleSheet.create({ - field: { - rowGap: 6, - }, - input: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 10, - borderWidth: 1, - paddingHorizontal: 12, - paddingVertical: 12, - }, - inputText: { - color: '#111827', - }, - label: { - color: '#6b7280', - fontSize: 13, - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 16, - }, - title: { - color: '#111827', - fontSize: 24, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md deleted file mode 100644 index 314f19ea..00000000 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Add cross-platform date selection to the app using Expo UI's date/time picker. \ No newline at end of file diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx deleted file mode 100644 index c50fd338..00000000 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/reference/App.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import DateTimePicker from '@expo/ui/community/datetime-picker' -import { useState } from 'react' -import { StyleSheet, Text, TextInput, View } from 'react-native' - -export default function App() { - const [name, setName] = useState('') - const [date, setDate] = useState(new Date()) - - return ( - - New reservation - - - Guest name - - - - - Date - { - if (selectedDate) { - setDate(selectedDate) - } - }} - /> - {date.toDateString()} - - - ) -} - -const styles = StyleSheet.create({ - field: { - rowGap: 6, - }, - input: { - backgroundColor: '#f9fafb', - borderColor: '#e5e7eb', - borderRadius: 10, - borderWidth: 1, - paddingHorizontal: 12, - paddingVertical: 12, - }, - inputText: { - color: '#111827', - }, - label: { - color: '#6b7280', - fontSize: 13, - }, - screen: { - backgroundColor: '#fff', - flex: 1, - padding: 20, - rowGap: 16, - }, - title: { - color: '#111827', - fontSize: 24, - fontWeight: '700', - }, -}) diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml deleted file mode 100644 index 3cea615a..00000000 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-no-android-open/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: community-datetime-import - description: "Must import DateTimePicker from @expo/ui/community/datetime-picker." - - id: no-android-open-api - description: "Must not use DateTimePickerAndroid.open." - - id: controlled-date-value - description: "Must keep selected Date in controlled state." - - id: handles-undefined-date - description: "Must guard onChange date being undefined when events cancel." diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md deleted file mode 100644 index 66e71b4c..00000000 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Add cross-platform date and time selection to App.tsx using Expo UI, handling any platform differences gracefully. \ No newline at end of file diff --git a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml deleted file mode 100644 index eb5fac4c..00000000 --- a/evals/expo-ui/04-rn-expo-ui-datetimepicker-unsupported-props/requirements.yaml +++ /dev/null @@ -1,13 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: supported-props-only - description: "Must configure the picker using only props supported by @expo/ui/community/datetime-picker (such as value/onValueChange and its display/mode options), not props specific to @react-native-community/datetimepicker." - - id: uses-onchange-or-onvaluechange - description: "Must handle date changes through onChange or onValueChange." - - id: fallback-for-platform-differences - description: "Must render a visible text fallback for a date/time mode that is not available on the current platform." - - id: no-react-native-community-datetimepicker-import - description: "Must not import @react-native-community/datetimepicker directly." diff --git a/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/app/App.tsx b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/app/App.tsx similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/app/App.tsx rename to evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/app/App.tsx diff --git a/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/prompt.md b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/prompt.md similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/prompt.md rename to evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/prompt.md diff --git a/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/reference/App.tsx b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/reference/App.tsx similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/reference/App.tsx rename to evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/reference/App.tsx diff --git a/evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml similarity index 100% rename from evals/expo-ui/05-rn-expo-ui-pagerview-drop-in/requirements.yaml rename to evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml diff --git a/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/app/App.tsx b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/app/App.tsx similarity index 100% rename from evals/expo-ui/06-rn-expo-ui-material-colors-symbols/app/App.tsx rename to evals/expo-ui/05-rn-expo-ui-material-colors-symbols/app/App.tsx diff --git a/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/prompt.md b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/prompt.md similarity index 100% rename from evals/expo-ui/06-rn-expo-ui-material-colors-symbols/prompt.md rename to evals/expo-ui/05-rn-expo-ui-material-colors-symbols/prompt.md diff --git a/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx similarity index 100% rename from evals/expo-ui/06-rn-expo-ui-material-colors-symbols/reference/App.tsx rename to evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx diff --git a/evals/expo-ui/06-rn-expo-ui-material-colors-symbols/requirements.yaml b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/requirements.yaml similarity index 100% rename from evals/expo-ui/06-rn-expo-ui-material-colors-symbols/requirements.yaml rename to evals/expo-ui/05-rn-expo-ui-material-colors-symbols/requirements.yaml diff --git a/evals/expo-ui/07-rn-expo-ui-native-state-text-input/app/App.tsx b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/app/App.tsx similarity index 100% rename from evals/expo-ui/07-rn-expo-ui-native-state-text-input/app/App.tsx rename to evals/expo-ui/06-rn-expo-ui-native-state-text-input/app/App.tsx diff --git a/evals/expo-ui/07-rn-expo-ui-native-state-text-input/prompt.md b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/prompt.md similarity index 100% rename from evals/expo-ui/07-rn-expo-ui-native-state-text-input/prompt.md rename to evals/expo-ui/06-rn-expo-ui-native-state-text-input/prompt.md diff --git a/evals/expo-ui/07-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx similarity index 100% rename from evals/expo-ui/07-rn-expo-ui-native-state-text-input/reference/App.tsx rename to evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx diff --git a/evals/expo-ui/07-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml similarity index 100% rename from evals/expo-ui/07-rn-expo-ui-native-state-text-input/requirements.yaml rename to evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml diff --git a/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx rename to evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/app/App.tsx diff --git a/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/prompt.md b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/prompt.md similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/prompt.md rename to evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/prompt.md diff --git a/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx rename to evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx diff --git a/evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml similarity index 100% rename from evals/expo-ui/08-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml rename to evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/requirements.yaml diff --git a/paper/benchmark-methodology-whitepaper.tex b/paper/benchmark-methodology-whitepaper.tex index 031ab701..13fdb6b0 100644 --- a/paper/benchmark-methodology-whitepaper.tex +++ b/paper/benchmark-methodology-whitepaper.tex @@ -74,7 +74,7 @@ \section{React Native methodology} Asynchronous state & 13 & Async state/data-flow tasks with \texttt{TanStack Query}, \texttt{Zustand}, and \texttt{Jotai}. \\ Expo Router & 11 & Expo Router SDK 56 tasks covering import boundaries, layouts, native tabs, protected routes, static/server loaders, suspense, and not-found routing. \\ Expo SDK & 25 & Expo SDK 56 capability-module behavior covering permissions, media, FileSystem, notifications, updates, system UI, and native config. \\ -Expo UI & 8 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ +Expo UI & 7 & \texttt{@expo/ui} universal components, community drop-in replacements, native state, and platform-native entrypoints. \\ Lists & 18 & List rendering, item interactions, virtualization patterns, and sectioned data presentation. \\ Navigation & 13 & Screen transitions, stack/modal flows, route params, and navigation state handling. \\ React Native APIs & 9 & Core platform API usage such as layout, keyboard, accessibility, and device integration primitives. \\ @@ -594,7 +594,7 @@ \section{Conflict of Interest} The authors are affiliated with Callstack. The experiments used commercially available infrastructure acquired and operated independently; no direct sponsorship, funding, or editorial influence was provided for this work. \section{Conclusion} -The current repository state contains \textbf{135} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. +The current repository state contains \textbf{134} evals across the categories in \cref{tab:category-evals-scope}. The benchmark result snapshot reported below was run earlier on a \textbf{66}-eval suite: we evaluated \textbf{18} solver models with \textbf{10 repeated runs per model} under the same pipeline and scoring rules. Across completed runs, the highest mean \texttt{weightedAverageScore} was \textbf{0.961} (\textbf{96.1\%}, model: \texttt{composer-2}); the median across models was \textbf{0.761} (\textbf{76.1\%}). Category-level analysis (\cref{fig:model-comparison}) shows strongest performance on \textbf{navigation} and \textbf{react native apis}, while \textbf{animation} remains the weakest and most discriminative category; \textbf{lists} and \textbf{async state} provide additional separation among otherwise closely clustered models. Recurring failures were concentrated in behavior-heavy requirements, especially animation dynamics and async-state consistency/invalidation logic. Two practical implications follow. First, React Native development difficulty is not uniform: models that are competitive on navigation and structural code generation can still be unreliable on behavior-heavy work, where correctness depends on timing, gesture/animation dynamics, and state invalidation semantics. For practitioners, this suggests applying the most scrutiny (and the most automated protection via tests and runtime validation) to animation and async-state code paths, even when a model performs strongly overall. Second, requirement-level evaluation yields actionable signals: per-requirement verdict traces support targeted prompt iteration, scaffolding improvements, and dataset evolution without collapsing all behavior into a single task-level pass/fail. From 82ee332d20c57cf77e4954e69c43d424b5a28aa8 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 3 Jul 2026 10:47:11 +0400 Subject: [PATCH 26/32] fix(evals): correct SDK 56 API usage and eval design across expo categories Review pass over the new expo-sdk/expo-router/expo-ui evals: - Fix references that misused the pinned SDK 56 packages (File.text() await, MediaLibrary.Asset.create, ExpoCalendar type, contacts address/image fields, Compose background modifier, ObservableState TextField wiring, swift-ui VStack, expo-router theming imports) - Re-base expo-ui/03 on the real DateTimePicker cancellation API (onDismiss; dialog pickers mount on press, unmount on close) - Make expo-router/11 winnable under the solver contract (catch-all placement is graded; no baseline deletion required) and move expo-router/09's server-only module outside the route directory - Derive iOS location accuracy from ios.accuracy, keep CameraView mounted while toggling active, wire real download progress, persist limited-access notice, drop dead/duplicated/baseline-satisfied requirements, de-leak prompts that named the graded APIs - Rewrite bug-report-framed prompts as forward-looking migrations - Pin migration-source packages in testbench and add a scoped typecheck gate (evals/tsconfig.expo.json) to CI Co-Authored-By: Claude Fable 5 --- bun.lock | 13 ++++ .../app/_layout.tsx | 8 +- .../reference/_layout.tsx | 3 +- .../requirements.yaml | 8 +- .../requirements.yaml | 11 ++- .../reference/_layout.tsx | 6 +- .../requirements.yaml | 10 +-- .../reference/_layout.tsx | 5 +- .../requirements.yaml | 8 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../reference/_layout.tsx | 2 - .../reference/app/_layout.tsx | 4 + .../reference/{ => app}/index.tsx | 0 .../reference/{ => app}/profile.tsx | 2 +- .../lib}/profile.server.ts | 0 .../reference/server/profile.server.ts | 3 - .../requirements.yaml | 9 +-- .../prompt.md | 2 +- .../app/+not-found.tsx | 9 --- .../app/[...slug].tsx | 12 --- .../prompt.md | 2 +- .../reference/_layout.tsx | 5 +- .../requirements.yaml | 8 +- .../app/App.tsx | 3 +- .../prompt.md | 2 +- .../reference/App.tsx | 41 ++++++++-- .../prompt.md | 2 +- .../reference/App.tsx | 15 ++-- .../reference/App.tsx | 23 +++--- .../requirements.yaml | 10 +-- .../app/app.config.ts | 1 + .../reference/App.tsx | 13 +--- .../requirements.yaml | 10 +-- .../reference/App.tsx | 12 +-- .../requirements.yaml | 10 +-- .../app/App.tsx | 2 +- .../prompt.md | 2 +- .../reference/App.tsx | 2 +- .../requirements.yaml | 8 +- .../reference/App.tsx | 13 +++- .../requirements.yaml | 12 +-- .../reference/App.tsx | 6 +- .../reference/App.tsx | 4 +- .../reference/App.tsx | 20 +++-- .../reference/App.tsx | 8 +- .../prompt.md | 2 +- .../reference/App.tsx | 74 +++++++++++++------ .../requirements.yaml | 14 ++-- .../reference/App.tsx | 3 +- .../reference/App.tsx | 7 +- .../requirements.yaml | 8 +- .../reference/App.tsx | 16 +++- evals/tsconfig.expo.json | 20 +++++ package.json | 3 +- testbench/package.json | 3 + 56 files changed, 281 insertions(+), 222 deletions(-) delete mode 100644 evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx create mode 100644 evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/{ => app}/index.tsx (100%) rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/{ => app}/profile.tsx (83%) rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/{app/server => reference/lib}/profile.server.ts (100%) delete mode 100644 evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts delete mode 100644 evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx delete mode 100644 evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx create mode 100644 evals/tsconfig.expo.json diff --git a/bun.lock b/bun.lock index 1c46b114..2b44f9d2 100644 --- a/bun.lock +++ b/bun.lock @@ -33,6 +33,7 @@ "version": "1.0.0", "dependencies": { "@expo/ui": "~56.0.18", + "@gorhom/bottom-sheet": "^5.2.6", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -62,11 +63,13 @@ "expo-task-manager": "~56.0.19", "expo-updates": "~56.0.19", "expo-video": "~56.1.4", + "expo-video-thumbnails": "~56.0.3", "jotai": "^2.18.0", "react": "19.2.3", "react-native": "0.85.3", "react-native-gesture-handler": "~2.31.1", "react-native-keyboard-controller": "1.21.6", + "react-native-pager-view": "8.0.1", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "~5.7.0", "react-native-screens": "4.25.2", @@ -353,6 +356,10 @@ "@expo/xcpretty": ["@expo/xcpretty@4.4.4", "", { "dependencies": { "@babel/code-frame": "^7.20.0", "chalk": "^4.1.0", "js-yaml": "^4.1.0" }, "bin": { "excpretty": "build/cli.js" } }, "sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw=="], + "@gorhom/bottom-sheet": ["@gorhom/bottom-sheet@5.2.14", "", { "dependencies": { "@gorhom/portal": "1.0.14", "invariant": "^2.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-native": "*", "react": "*", "react-native": "*", "react-native-gesture-handler": ">=2.16.1", "react-native-reanimated": ">=3.16.0 || >=4.0.0-" }, "optionalPeers": ["@types/react", "@types/react-native"] }, "sha512-uLQFlDjp9z+jrOFcMSEldPqL5JdaXL3vXOh+juhwoNvXgTsEorJLjHTugXu+YccAG/0KJnShzKCrb71MHBsvJg=="], + + "@gorhom/portal": ["@gorhom/portal@1.0.14", "", { "dependencies": { "nanoid": "^3.3.1" }, "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A=="], + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], @@ -1079,6 +1086,8 @@ "expo-video": ["expo-video@56.1.4", "", { "peerDependencies": { "expo": "*", "react": "*", "react-native": "*" } }, "sha512-8mXZOnb7ZsWneDlcnRf0M2Ox9eb5dGnNiGiCkj9bwLPY+3jM2Pc1t5ymNUuhw8lSpT/rOnE0J0/81Y3+0k2Zcw=="], + "expo-video-thumbnails": ["expo-video-thumbnails@56.0.3", "", { "peerDependencies": { "expo": "*" } }, "sha512-V3uqwOeT3KzHxiO32cAGC4ldP45wlgUc22w2ejPdo5uCMM6rm1FakKxccMPPqaJQGn4EUUVGIeGZlzR5tBmr+Q=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], @@ -1695,6 +1704,8 @@ "react-native-keyboard-controller": ["react-native-keyboard-controller@1.21.6", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.2.1" }, "peerDependencies": { "react": "*", "react-native": "*", "react-native-reanimated": ">=3.0.0" } }, "sha512-nAXCmar/W8Gn4iQV7O5fAVuTh57JszCsqTS+cfR95WFOLR/AfbwfPz/+sWyz/q2SOIe2VpyQzq6hzYiwErhqqw=="], + "react-native-pager-view": ["react-native-pager-view@8.0.1", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-pGOne2o0y0HOQLrlTLcGgOE48uJlqSZHRRwdW8nL6JJozMkPGJYi/G9e0EsJoWFpXYONjiDgr8IwxC4F6/r7Lg=="], + "react-native-reanimated": ["react-native-reanimated@4.3.1", "", { "dependencies": { "react-native-is-edge-to-edge": "^1.3.1", "semver": "^7.7.3" }, "peerDependencies": { "react": "*", "react-native": "0.81 - 0.85", "react-native-worklets": "0.8.x" } }, "sha512-KhGsS0YkCA+gusgyzlf9hnqzVPIR398KTpqXyqq/+yYJJPAvyEEPKcxlB0xtOOXSMrR2A9uRKVARVQhZwrOh+Q=="], "react-native-safe-area-context": ["react-native-safe-area-context@5.7.0", "", { "peerDependencies": { "react": "*", "react-native": "*" } }, "sha512-/9/MtQz8ODphjsLdZ+GZAIcC/RtoqW9EeShf7Uvnfgm/pzYrJ75y3PV/J1wuAV1T5Dye5ygq4EAW20RoBq0ABQ=="], @@ -2047,6 +2058,8 @@ "@expo/ws-tunnel/ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "@gorhom/portal/nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx index 0031e553..64b95286 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx @@ -1,14 +1,12 @@ import { DefaultTheme, ThemeProvider } from '@react-navigation/native' -import { createNativeStackNavigator } from '@react-navigation/native-stack' - -const Stack = createNativeStackNavigator() +import { Stack } from 'expo-router' export default function Layout() { return ( - + - + ) } diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx index 5690fe1b..e5880c55 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/reference/_layout.tsx @@ -1,5 +1,4 @@ -import { Stack } from 'expo-router' -import { DefaultTheme, ThemeProvider } from 'expo-router/react-navigation' +import { DefaultTheme, Stack, ThemeProvider } from 'expo-router' export default function Layout() { return ( diff --git a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml index b9d0d4fb..c089f1b5 100644 --- a/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml +++ b/evals/expo-router/01-rn-expo-router-sdk56-react-navigation-imports/requirements.yaml @@ -5,10 +5,10 @@ inputs: - app/index.tsx requirements: - id: imports-from-expo-router - description: "Must import router hooks/themes/navigation helpers from expo-router exports rather than direct @react-navigation packages." + description: 'Must import router hooks/themes/navigation helpers from expo-router exports rather than direct @react-navigation packages.' - id: no-direct-react-navigation-imports - description: "Must not import from @react-navigation/native or @react-navigation/native-stack in app route files." + description: 'Must not import from @react-navigation/native or @react-navigation/native-stack in app route files.' - id: keeps-file-system-layout - description: "Must keep navigation defined through Expo Router layout and route files." + description: 'Must keep navigation defined through Expo Router layout and route files.' - id: migrates-theme-import-to-expo-router - description: "Must import React Navigation theming such as ThemeProvider and DefaultTheme from expo-router/react-navigation, and keep wrapping the Stack in it, rather than dropping it or importing from @react-navigation/native." + description: 'Must import React Navigation theming such as ThemeProvider and DefaultTheme from expo-router itself, and keep wrapping the Stack in it, rather than dropping it, importing from @react-navigation/native, or using the deprecated expo-router/react-navigation subpath.' diff --git a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml index 84174091..9c13c793 100644 --- a/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml +++ b/evals/expo-router/02-rn-expo-router-stack-layout-not-native-stack-import/requirements.yaml @@ -3,15 +3,14 @@ inputs: files: - app/_layout.tsx - app/index.tsx - - app/details.tsx requirements: - id: uses-expo-router-stack - description: "Must render Stack from expo-router in _layout.tsx and not call createNativeStackNavigator or NavigationContainer." + description: 'Must render Stack from expo-router in _layout.tsx and not call createNativeStackNavigator or NavigationContainer.' - id: navigates-to-details - description: "Must navigate from the Products screen to the details route using expo-router Link or router navigation." + description: 'Must navigate from the Products screen to the details route using expo-router Link or router navigation.' - id: passes-id-param - description: "Must pass the product id as a route parameter when navigating to details." + description: 'Must pass the product id as a route parameter when navigating to details.' - id: details-reads-id-with-hook - description: "The details screen must read the id from the route with useLocalSearchParams or useGlobalSearchParams." + description: 'The details screen must read the id from the route with useLocalSearchParams or useGlobalSearchParams.' - id: details-renders-id - description: "The details screen must render the received id value." + description: 'The details screen must render the received id value.' diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx index 61abb1b7..0d540947 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/reference/_layout.tsx @@ -4,8 +4,10 @@ export default function Layout() { return ( - Home - + Home + Settings diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml index a7484665..e9efe4ea 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml @@ -6,12 +6,8 @@ inputs: - app/settings.tsx requirements: - id: home-icon-default-and-selected - description: "The Home trigger must render NativeTabs.Trigger.Icon with sf set to a default symbol \"house\" and a selected symbol \"house.fill\"." + description: 'The Home trigger must render NativeTabs.Trigger.Icon with sf set to a default symbol "house" and a selected symbol "house.fill".' - id: settings-badge-value - description: "The Settings trigger must render NativeTabs.Trigger.Badge with the value 2." + description: 'The Settings trigger must render NativeTabs.Trigger.Badge with the value 2.' - id: uses-trigger-child-apis - description: "Must configure per-tab presentation through NativeTabs.Trigger.Icon/Badge/Label child components." - - id: route-name-alignment - description: "Must align tab trigger names with the file routes (index, settings)." - - id: no-generic-tabs-api - description: "Must not use generic Expo Router Tabs for this native-tabs task." + description: 'Must configure per-tab presentation through NativeTabs.Trigger.Icon/Badge/Label child components.' diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx index a71b6cef..ae7faef3 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx @@ -5,11 +5,12 @@ const signedIn = false export default function Layout() { return ( + - + - + ) diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml index a2163165..23ee09e5 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -7,10 +7,10 @@ inputs: - app/sign-in.tsx requirements: - id: uses-stack-protected - description: "Must gate routes with Stack.Protected, since the app uses a Stack layout." + description: 'Must gate routes with Stack.Protected, since the app uses a Stack layout.' - id: signed-out-fallback - description: "Must provide a deterministic signed-out fallback route." + description: 'The layout must keep an unguarded, always-available route (such as index or the signed-out sign-in screen) declared so signed-out users deterministically land somewhere instead of a guarded screen.' - id: guard-boolean-explicit - description: "Must pass explicit guard booleans derived from auth state." + description: 'Must pass explicit guard booleans derived from auth state.' - id: no-redirect-loop - description: "Must avoid unconditional redirects that can loop between protected and sign-in routes." + description: 'Must avoid unconditional redirects that can loop between protected and sign-in routes.' diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md index 483a5a23..437a775d 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/prompt.md @@ -1 +1 @@ -Navigate between routes in an Expo Router app and read params on the destination screen. \ No newline at end of file +On the Products screen, make the "Open details" link carry the product's id and its currently selected tab (both from the PRODUCT constant) to the details screen. The details screen must read those values from the route and render both. It should also handle being opened directly via a deep link where the values are missing, showing sensible fallbacks instead of crashing or rendering blanks. Keep everything passed between the screens serializable — no functions, class instances, or nested objects. diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md index 368c25b7..7be4cc96 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md @@ -1 +1 @@ -The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into the server-only module and expose it through a route loader that returns the profile name, then render the name in the client with useLoaderData so the secret never ships in the client bundle. \ No newline at end of file +The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into a server-only module that lives outside the route directory (for example lib/profile.server.ts at the project root, so the router never treats it as a route) and expose it through a route loader that returns the profile name, then render the name in the client with useLoaderData so the secret never ships in the client bundle. diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx deleted file mode 100644 index 61625f48..00000000 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import { Stack } from 'expo-router' -export default function Layout() { return } diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx new file mode 100644 index 00000000..7de3ab83 --- /dev/null +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx @@ -0,0 +1,4 @@ +import { Stack } from 'expo-router' +export default function Layout() { + return +} diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/index.tsx similarity index 100% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/index.tsx diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx similarity index 83% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx index 536f1be1..b8666b51 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx @@ -1,6 +1,6 @@ import { useLoaderData } from 'expo-router' import { Text } from 'react-native' -import { getProfile } from './server/profile.server' +import { getProfile } from '../lib/profile.server' export async function loader() { return getProfile() diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts similarity index 100% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/app/server/profile.server.ts rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts deleted file mode 100644 index 5a6cd4e6..00000000 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/server/profile.server.ts +++ /dev/null @@ -1,3 +0,0 @@ -export async function getProfile() { - return { name: process.env.PROFILE_NAME ?? 'Expo' } -} diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml index d0626103..128a003c 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml @@ -4,13 +4,12 @@ inputs: - app/_layout.tsx - app/index.tsx - app/profile.tsx - - app/server/profile.server.ts requirements: - id: server-only-code-isolated - description: "Must place server-only secret/env access in a server-only module or loader boundary." + description: 'Must place server-only secret/env access in a server-only module or loader boundary.' - id: client-route-uses-loader-data - description: "Must render route UI from useLoaderData rather than importing secrets directly." + description: 'Must render route UI from useLoaderData rather than importing secrets directly.' - id: static-loader-data-serializable - description: "Must return serializable data from loader functions." + description: 'Must return serializable data from loader functions.' - id: no-secret-in-client-component - description: "Must not read process.env secrets in the client component body." + description: 'Must not read process.env secrets in the client component body.' diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md index ff85e686..0218c12c 100644 --- a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md @@ -1 +1 @@ -The index route renders async content with React Suspense. Add a route-level SuspenseFallback that shows a "Loading…" indicator until the content resolves. \ No newline at end of file +The index route renders async content with React Suspense. Show a "Loading…" indicator while the content resolves, implemented at the route level rather than through a global wrapper, and keep the route's default export rendering the resolved content. diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx deleted file mode 100644 index 802a728b..00000000 --- a/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/+not-found.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Text, View } from 'react-native' - -export default function NotFound() { - return ( - - Not found - - ) -} diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx deleted file mode 100644 index 645b9c16..00000000 --- a/evals/expo-router/11-rn-expo-router-not-found-route-priority/app/[...slug].tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useLocalSearchParams } from 'expo-router' -import { Text, View } from 'react-native' - -export default function CatchAll() { - const { slug } = useLocalSearchParams<{ slug?: string[] }>() - - return ( - - Docs: {slug?.join('/') ?? 'index'} - - ) -} diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md b/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md index 18d8cbd4..1c82c79e 100644 --- a/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md +++ b/evals/expo-router/11-rn-expo-router-not-found-route-priority/prompt.md @@ -1 +1 @@ -Implement a +not-found screen that shows a clear "this screen does not exist" message and a link back to the home screen, and scope the docs catch-all route so it does not shadow the not-found route for unknown paths. \ No newline at end of file +Add a docs section to the app: any path under /docs/ should render a screen that shows the requested slug. Every other unknown path should land on a screen with a clear "this screen does not exist" message and a link back to the home screen — make sure unknown non-docs paths reach that screen rather than the docs renderer. diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx index 61625f48..99996670 100644 --- a/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx +++ b/evals/expo-router/11-rn-expo-router-not-found-route-priority/reference/_layout.tsx @@ -1,2 +1,5 @@ import { Stack } from 'expo-router' -export default function Layout() { return } + +export default function Layout() { + return +} diff --git a/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml b/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml index 9add2a85..f0eb1fc1 100644 --- a/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml +++ b/evals/expo-router/11-rn-expo-router-not-found-route-priority/requirements.yaml @@ -3,12 +3,10 @@ inputs: files: - app/_layout.tsx - app/index.tsx - - app/+not-found.tsx - - app/[...slug].tsx requirements: - id: plus-not-found-route - description: "Must implement +not-found.tsx as the not-found route." + description: 'Must implement +not-found.tsx as the not-found route.' - id: not-found-message-and-home-link - description: "The +not-found screen must render a clear not-found message and a Link to the home route \"/\"." + description: 'The +not-found screen must render a clear not-found message and a Link to the home route "/".' - id: catch-all-scoped-not-shadowing - description: "Must scope the catch-all route (for example under docs/) so unknown paths fall through to +not-found instead of being caught by the catch-all." + description: 'Must create the docs catch-all route scoped under the docs directory (for example app/docs/[...slug].tsx) rather than as a root-level catch-all, which would shadow the not-found route for unknown non-docs paths.' diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx index 146036c0..bc850e98 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/app/App.tsx @@ -1,9 +1,10 @@ +import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' type PermissionState = 'undetermined' | 'granted' | 'denied' export default function App() { - const permissionState: PermissionState = 'undetermined' + const [permissionState] = useState('undetermined') const handleRequestPermission = () => {} const handleOpenSettings = () => {} diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md index 524f9da1..6f9ae0e9 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md @@ -1 +1 @@ -Wire this camera screen up to expo-camera. Request camera permission only when the user taps "Enable Camera" (never on mount), and guard against overlapping prompts while a request is already in flight. Render CameraView in the preview area only once permission is granted, and keep the "Camera is off" fallback for every other state. When permission is permanently blocked (denied with canAskAgain false), show the Settings recovery block and open the system settings with Linking.openSettings() instead of prompting again. Re-check the permission whenever the app returns to the foreground so a grant made in Settings is picked up. +Wire this camera screen up to expo-camera. Request camera permission only when the user taps "Enable Camera" (never on mount), and guard against overlapping prompts while a request is already in flight. Render CameraView in the preview area only once permission is granted, and keep the "Camera is off" fallback for every other state. When access is permanently blocked and the app can no longer prompt, show the Settings recovery block and take the user to the system settings instead of prompting again. Re-check the permission whenever the app returns to the foreground so a grant made in Settings is picked up. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx index 1207a065..6505e516 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx @@ -1,6 +1,13 @@ import { CameraView, useCameraPermissions } from 'expo-camera' import { useEffect, useRef, useState } from 'react' -import { AppState, Pressable, StyleSheet, Switch, Text, View } from 'react-native' +import { + AppState, + Pressable, + StyleSheet, + Switch, + Text, + View, +} from 'react-native' export default function App() { const [permission, requestPermission] = useCameraPermissions() @@ -10,12 +17,13 @@ export default function App() { useEffect(() => { const sub = AppState.addEventListener('change', (state) => - setAppActive(state === 'active'), + setAppActive(state === 'active') ) return () => sub.remove() }, []) - const cameraActive = Boolean(permission?.granted) && appActive && cameraEnabled + const cameraActive = + Boolean(permission?.granted) && appActive && cameraEnabled const handleTakePhoto = async () => { if (!permission?.granted) { @@ -31,11 +39,18 @@ export default function App() { {permission?.granted ? ( - cameraActive ? ( - - ) : ( - Camera paused - ) + <> + + {!cameraActive && ( + + Camera paused + + )} + ) : ( Camera access required )} @@ -78,6 +93,16 @@ const styles = StyleSheet.create({ height: '100%', width: '100%', }, + pausedOverlay: { + alignItems: 'center', + backgroundColor: '#1f2937', + bottom: 0, + justifyContent: 'center', + left: 0, + position: 'absolute', + right: 0, + top: 0, + }, preview: { alignItems: 'center', aspectRatio: 3 / 4, diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md index 66d26ba2..08bf3c05 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md @@ -1 +1 @@ -Wire up the Choose from Library button to expo-image-picker. Launch the picker only from the button, show the selected image in the preview, and keep a stable empty state when the user cancels. Read the current result shape (result.canceled and result.assets) and current mediaTypes so a cancel never crashes. +Wire up the Choose from Library button to expo-image-picker. Launch the picker only from the button press, show the selected image in the preview, and keep a stable empty state when the user cancels — cancellation must never crash. diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx index f9962cb2..b7b2cb96 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx @@ -5,6 +5,7 @@ import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { const [videoUri, setVideoUri] = useState(null) const [status, setStatus] = useState('No video selected') + const [accessNotice, setAccessNotice] = useState(null) const handlePickVideo = async () => { const existing = await ImagePicker.getMediaLibraryPermissionsAsync() @@ -12,16 +13,18 @@ export default function App() { ? existing : await ImagePicker.requestMediaLibraryPermissionsAsync(false) if (!permission.granted) { - setStatus( + setAccessNotice( permission.canAskAgain ? 'Video access denied' - : 'Enable video access in Settings', + : 'Enable video access in Settings' ) return } - if (permission.accessPrivileges === 'limited') { - setStatus('Limited library access — only selected videos are available') - } + setAccessNotice( + permission.accessPrivileges === 'limited' + ? 'Limited library access — only selected videos are available' + : null + ) const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['videos'], videoMaxDuration: 60, @@ -53,6 +56,8 @@ export default function App() { )} + {accessNotice ? {accessNotice} : null} + {videoUri ? {status} : null} diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx index 04945e09..b2f80fbe 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/reference/App.tsx @@ -7,25 +7,20 @@ export default function App() { useState(null) const handleRefresh = async () => { - const next = await Location.requestForegroundPermissionsAsync() - setPermission(next) - if (!next.granted) return - // Touch the position API with explicit accuracy options; do not assume the - // grant implies precise location. - await Location.getCurrentPositionAsync({ - accuracy: Location.Accuracy.Balanced, - }) + setPermission(await Location.requestForegroundPermissionsAsync()) } const permissionStatus = permission?.status ?? 'undetermined' - // iOS exposes an authorization scope; Android exposes fine/coarse accuracy. - // A granted permission can still be approximate, so do not assume precise. + // iOS exposes a full/reduced accuracy authorization; Android exposes + // fine/coarse accuracy. A granted permission can still be approximate, + // so do not assume precise. const androidAccuracy = permission?.android?.accuracy - const iosScope = permission?.ios?.scope - const preciseAccuracy = androidAccuracy === 'fine' + const iosAccuracy = permission?.ios?.accuracy + const preciseAccuracy = androidAccuracy === 'fine' || iosAccuracy === 'full' const accuracyDetail = - androidAccuracy ?? (iosScope ? `iOS ${iosScope}` : undefined) - const blocked = permission != null && !permission.granted && !permission.canAskAgain + androidAccuracy ?? (iosAccuracy ? `iOS ${iosAccuracy}` : undefined) + const blocked = + permission != null && !permission.granted && !permission.canAskAgain return ( diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml index 7cbfad3f..07ce8357 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml @@ -4,12 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-location-permission-details - description: "Must inspect platform permission details such as permission.ios?.scope or permission.android?.accuracy when present." + description: 'Must inspect platform permission details such as permission.ios?.accuracy or permission.android?.accuracy when present.' - id: does-not-assume-precise-location - description: "Must not assume granted permission implies precise/exact location accuracy." + description: 'Must not assume granted permission implies precise/exact location accuracy.' - id: fallback-for-approximate - description: "Must render a specific approximate-location fallback or explanation." - - id: explicit-location-options - description: "Must use explicit getCurrentPositionAsync accuracy options." + description: 'Must render a specific approximate-location fallback or explanation.' - id: settings-recovery-for-blocked - description: "Must offer Linking.openSettings() when permission canAskAgain is false." + description: 'Must offer Linking.openSettings() when permission canAskAgain is false.' diff --git a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts index b67f76a0..964db524 100644 --- a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts +++ b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/app/app.config.ts @@ -3,6 +3,7 @@ export default { name: 'notification-config-audit', slug: 'notification-config-audit', notification: { + color: '#111827', icon: './assets/notification.png', }, }, diff --git a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx index 87e1f802..4a5b242f 100644 --- a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx +++ b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/reference/App.tsx @@ -1,18 +1,7 @@ -import * as Notifications from 'expo-notifications' import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const handleSendTest = async () => { - const permission = await Notifications.getPermissionsAsync() - if (!permission.granted) { - const requested = await Notifications.requestPermissionsAsync() - if (!requested.granted) return - } - await Notifications.scheduleNotificationAsync({ - content: { title: 'Test notification', body: 'Configured via app.config.ts.' }, - trigger: null, - }) - } + const handleSendTest = () => {} return ( diff --git a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml index b698d4c7..3557b26a 100644 --- a/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml +++ b/evals/expo-sdk/11-rn-expo-notifications-config-plugin-no-notification-field/requirements.yaml @@ -5,12 +5,12 @@ inputs: - app/app.config.ts requirements: - id: uses-expo-notifications-plugin - description: "Must configure expo-notifications through the plugins array in app.config.ts/app.json." + description: 'Must configure expo-notifications through the plugins array in app.config.ts/app.json.' - id: removes-top-level-notification - description: "Must not leave a top-level expo.notification object in app config." + description: 'Must not leave a top-level expo.notification object in app config.' - id: preserves-icon-color-channel - description: "Must preserve native notification icon/color/default channel configuration inside the plugin options." + description: 'Must preserve the existing notification icon and color inside the expo-notifications plugin options and configure an Android default notification channel there (defaultChannel).' - id: background-remote-plugin-option - description: "Must configure enableBackgroundRemoteNotifications in plugin options when background remote notifications are required." + description: 'Must configure enableBackgroundRemoteNotifications in plugin options when background remote notifications are required.' - id: config-remains-static-export - description: "Must keep app config as a valid exported object or config function." + description: 'Must keep app config as a valid exported object or config function.' diff --git a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx index c5b55336..fdfbed5a 100644 --- a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx +++ b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/reference/App.tsx @@ -1,12 +1,6 @@ import { Directory, File, Paths } from 'expo-file-system' import { useEffect, useMemo, useState } from 'react' -import { - Pressable, - StyleSheet, - Text, - TextInput, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' export default function App() { const [draft, setDraft] = useState('') @@ -14,12 +8,12 @@ export default function App() { const noteFile = useMemo( () => new File(new Directory(Paths.cache, 'notes'), 'daily.txt'), - [], + [] ) const loadNote = async () => { try { - const contents = noteFile.text() + const contents = await noteFile.text() setDraft(contents) setStatus('Loaded saved note.') } catch { diff --git a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml index f6c66312..9eb65a96 100644 --- a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml +++ b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml @@ -4,12 +4,10 @@ inputs: - app/App.tsx requirements: - id: imports-file-directory-paths - description: "Must import File, Directory, and Paths from expo-file-system." + description: 'Must import File, Directory, and Paths from expo-file-system.' - id: creates-directory-idempotently - description: "Must create a Directory under Paths.cache or Paths.document with idempotent/intermediates options." + description: 'Must create a Directory under Paths.cache or Paths.document with idempotent/intermediates options.' - id: uses-file-instance-read-write - description: "Must call File instance methods such as write() and text() for read/write operations." - - id: avoids-root-legacy-methods - description: "Must not call root readAsStringAsync/writeAsStringAsync/makeDirectoryAsync from expo-file-system." + description: 'Must call File instance methods such as write() and text() for read/write operations.' - id: handles-read-missing-file - description: "Must handle missing-file or first-run reads with fallback text instead of crashing." + description: 'Must handle missing-file or first-run reads with fallback text instead of crashing.' diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx index 3e1a08b6..9e591cea 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/app/App.tsx @@ -3,7 +3,7 @@ import { makeDirectoryAsync, readAsStringAsync, writeAsStringAsync, -} from 'expo-file-system' +} from 'expo-file-system/legacy' import { useState } from 'react' import { Pressable, StyleSheet, Text, View } from 'react-native' diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md index 6fe5243f..21919412 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md @@ -1 +1 @@ -A file helper is broken after an SDK upgrade — file operations crash at runtime. Fix it so the helper works with the current version of expo-file-system. \ No newline at end of file +Migrate the profile file helper off the legacy expo-file-system API to the SDK 56 object API (Directory, File, Paths). Keep the save/load behavior identical. diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx index 78a4cc54..46ac579c 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/reference/App.tsx @@ -20,7 +20,7 @@ export default function App() { const loadProfile = async () => { try { - const contents = PROFILE_FILE.text() + const contents = await PROFILE_FILE.text() setMessage(contents) } catch (error) { setMessage(`Load failed: ${String(error)}`) diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml index 405f0a20..8bf13380 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/requirements.yaml @@ -4,10 +4,8 @@ inputs: - app/App.tsx requirements: - id: no-root-legacy-import - description: "Must not import readAsStringAsync, writeAsStringAsync, downloadAsync, uploadAsync, getInfoAsync, or makeDirectoryAsync from the root expo-file-system module." - - id: legacy-import-if-needed - description: "Must import old helper methods from expo-file-system/legacy when retaining the legacy method style." + description: 'Must not import readAsStringAsync, writeAsStringAsync, downloadAsync, uploadAsync, getInfoAsync, or makeDirectoryAsync from the root expo-file-system module, and must not import them from expo-file-system/legacy in the final solution.' - id: object-api-preferred - description: "Must use File/Directory/Paths from expo-file-system for new read/write code." + description: 'Must use File/Directory/Paths from expo-file-system for new read/write code.' - id: keeps-uri-boundary-explicit - description: "Must keep file URI/path construction explicit instead of concatenating undefined documentDirectory/cacheDirectory root constants." + description: "Must build file paths with the object API's Paths/Directory instead of string-concatenating the legacy documentDirectory/cacheDirectory root constants." diff --git a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx index 529242cc..622b701d 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx +++ b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx @@ -23,8 +23,13 @@ export default function App() { try { const downloads = new Directory(Paths.document, 'downloads') downloads.create({ idempotent: true, intermediates: true }) - const file = await File.downloadFileAsync(REMOTE_URL, downloads) - setProgress(1) + const file = await File.downloadFileAsync(REMOTE_URL, downloads, { + onProgress: ({ bytesWritten, totalBytes }) => { + if (totalBytes > 0) { + setProgress(bytesWritten / totalBytes) + } + }, + }) setPhase('uploading') const body = new FormData() @@ -59,7 +64,9 @@ export default function App() { ) : null} - {phase === 'done' ? Upload complete. : null} + {phase === 'done' ? ( + Upload complete. + ) : null} {phase === 'error' ? ( Transfer failed. ) : null} diff --git a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml index 23e00448..ca57fd2d 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml +++ b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: uses-file-download-file-async - description: "Must use File.downloadFileAsync with a Directory or File destination from the object API." + description: 'Must use File.downloadFileAsync with a Directory or File destination from the object API.' - id: destination-directory-created - description: "Must create the destination Directory idempotently before downloading." + description: 'Must create the destination Directory idempotently before downloading.' - id: upload-uses-fetch-formdata - description: "Must upload using fetch with FormData or another current web-compatible API instead of root uploadAsync." - - id: no-root-download-upload-async - description: "Must not call root FileSystem.downloadAsync or uploadAsync from expo-file-system." + description: 'Must upload using fetch with FormData or another current web-compatible API instead of root uploadAsync.' + - id: download-progress-from-callback + description: 'Must drive the download progress UI from the download options onProgress callback rather than hardcoding progress values.' - id: download-error-state - description: "Must catch download/upload errors and render a deterministic failure state." + description: 'Must catch download/upload errors and render a deterministic failure state.' diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx index 182d94be..a56cc7f5 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx @@ -12,7 +12,9 @@ export default function App() { const saveToLibrary = async () => { setSaveState('saving') - const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) + const permission = await MediaLibrary.requestPermissionsAsync(true, [ + 'photo', + ]) if (!permission.granted) { setSaveState('denied') return @@ -21,7 +23,7 @@ export default function App() { const cache = new Directory(Paths.cache, 'posters') cache.create({ idempotent: true, intermediates: true }) const file = await File.downloadFileAsync(GENERATED_IMAGE_URI, cache) - await MediaLibrary.saveToLibraryAsync(file.uri) + await MediaLibrary.Asset.create(file.uri) setSaveState('saved') } catch { setSaveState('denied') diff --git a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx index 8c20bb3e..eabffb66 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx +++ b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/reference/App.tsx @@ -14,7 +14,9 @@ export default function App() { const saveToAlbum = async () => { setSaveState('saving') try { - const permission = await MediaLibrary.requestPermissionsAsync(true, ['photo']) + const permission = await MediaLibrary.requestPermissionsAsync(false, [ + 'photo', + ]) if (!permission.granted) { setSaveState('error') return diff --git a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx index ce026c00..104555e1 100644 --- a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx +++ b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/reference/App.tsx @@ -1,12 +1,6 @@ import * as Calendar from 'expo-calendar' import { useEffect, useRef, useState } from 'react' -import { - Pressable, - StyleSheet, - Text, - TextInput, - View, -} from 'react-native' +import { Pressable, StyleSheet, Text, TextInput, View } from 'react-native' type CalendarOption = { id: string @@ -19,7 +13,7 @@ export default function App() { const [eventTitle, setEventTitle] = useState('') const [status, setStatus] = useState('') - const calendarsRef = useRef([]) + const calendarsRef = useRef([]) const loadCalendars = async () => { const permission = await Calendar.requestCalendarPermissions() @@ -29,7 +23,9 @@ export default function App() { } const available = await Calendar.getCalendars(Calendar.EntityTypes.EVENT) - const writable = available.filter((calendar) => calendar.allowsModifications) + const writable = available.filter( + (calendar) => calendar.allowsModifications + ) if (writable.length === 0) { setStatus('No writable calendar available.') return @@ -37,7 +33,7 @@ export default function App() { calendarsRef.current = writable setCalendars( - writable.map((calendar) => ({ id: calendar.id, title: calendar.title })), + writable.map((calendar) => ({ id: calendar.id, title: calendar.title })) ) setSelectedId(writable[0].id) } @@ -74,7 +70,9 @@ export default function App() { onPress={() => setSelectedId(calendar.id)} style={[styles.chip, isActive && styles.chipActive]} > - + {calendar.title} diff --git a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx index b8d29168..f0f633e5 100644 --- a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx +++ b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/reference/App.tsx @@ -34,16 +34,16 @@ export default function App() { Contacts.ContactField.EMAILS, Contacts.ContactField.IMAGE, ], - { limit: 50 }, + { limit: 50 } ) setContacts( result.map((contact) => ({ id: contact.id, name: contact.fullName ?? 'Unnamed contact', - email: contact.emails?.[0]?.email, - imageUri: contact.image?.uri, - })), + email: contact.emails?.[0]?.address, + imageUri: contact.image ?? undefined, + })) ) setLoaded(true) } diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md index 0367f193..e49350c7 100644 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/prompt.md @@ -1 +1 @@ -Add cross-platform date and time selection to the appointment form using Expo UI's date/time picker. Keep the selected value in controlled state via onValueChange, guard against an undefined value when the user cancels, and render a text fallback for any date/time mode not available on the current platform. +Add cross-platform date and time selection to the appointment form using Expo UI's date/time picker. Keep the selection in controlled state so the form always reflects the current value. When the user closes the picker without choosing anything, the previous value must stay unchanged and the picker must remain reopenable. Render a text fallback for any date/time mode not available on the current platform. diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx index 6dddcd28..70d343ce 100644 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/reference/App.tsx @@ -1,16 +1,20 @@ import DateTimePicker from '@expo/ui/community/datetime-picker' import { useState } from 'react' -import { Platform, StyleSheet, Text, TextInput, View } from 'react-native' +import { + Platform, + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from 'react-native' export default function App() { const [title, setTitle] = useState('') const [startsAt, setStartsAt] = useState(new Date()) + const [activePicker, setActivePicker] = useState<'date' | 'time' | null>(null) - const updateStartsAt = (next?: Date) => { - if (next) { - setStartsAt(next) - } - } + const closePicker = () => setActivePicker(null) return ( @@ -32,24 +36,45 @@ export default function App() { updateStartsAt(next)} + onValueChange={(_event, next) => setStartsAt(next)} /> ) : ( - - updateStartsAt(next)} - /> - updateStartsAt(next)} - /> + <> + + setActivePicker('date')} + style={[styles.input, styles.grow]} + > + {startsAt.toDateString()} + + setActivePicker('time')} + style={[styles.input, styles.grow]} + > + + {startsAt.toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + })} + + + + {activePicker != null && ( + { + setStartsAt(next) + closePicker() + }} + onDismiss={closePicker} + /> + )} - Combined date and time selection is not available on this platform; pick each separately. + Combined date and time selection is not available on this + platform; pick each separately. - + )} @@ -64,8 +89,12 @@ const styles = StyleSheet.create({ field: { rowGap: 6, }, + grow: { + flex: 1, + }, inlineRow: { - rowGap: 8, + columnGap: 10, + flexDirection: 'row', }, input: { backgroundColor: '#f9fafb', @@ -75,6 +104,9 @@ const styles = StyleSheet.create({ paddingHorizontal: 12, paddingVertical: 12, }, + inputText: { + color: '#111827', + }, label: { color: '#6b7280', fontSize: 13, diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml index 21687144..4e632ec0 100644 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml @@ -4,14 +4,14 @@ inputs: - app/App.tsx requirements: - id: community-datetime-import - description: "Must import DateTimePicker from @expo/ui/community/datetime-picker." + description: 'Must import DateTimePicker from @expo/ui/community/datetime-picker.' - id: no-android-open-api - description: "Must not use DateTimePickerAndroid.open." + description: 'Must not use DateTimePickerAndroid.open.' - id: no-react-native-community-datetimepicker-import - description: "Must not import @react-native-community/datetimepicker directly." + description: 'Must not import @react-native-community/datetimepicker directly.' - id: controlled-value-via-onvaluechange - description: "Must keep the selected date/time in controlled state and update it through onValueChange." - - id: handles-undefined-value - description: "Must guard against the onValueChange value being undefined when the user cancels." + description: 'Must keep the selected date/time in controlled state and update it through onValueChange.' + - id: handles-dismissal-via-ondismiss + description: 'Must handle the picker being dismissed without a selection via onDismiss, not by expecting an undefined date from onValueChange.' - id: platform-mode-fallback - description: "Must render a visible text fallback for a date/time mode not available on the current platform." + description: 'Must render a visible text fallback for a date/time mode not available on the current platform.' diff --git a/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx index fa5f6403..d8c9c6c8 100644 --- a/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx +++ b/evals/expo-ui/05-rn-expo-ui-material-colors-symbols/reference/App.tsx @@ -1,4 +1,5 @@ import { Column, Host, Text, useMaterialColors } from '@expo/ui/jetpack-compose' +import { background } from '@expo/ui/jetpack-compose/modifiers' export default function App() { const colors = useMaterialColors() @@ -7,7 +8,7 @@ export default function App() { Today - + You have 3 tasks due diff --git a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx index de28ba3b..ec43048a 100644 --- a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx +++ b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -6,12 +6,7 @@ export default function App() { return ( Search - { - query.value = next - }} - /> + ) } diff --git a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml index f0214e91..7e24b91d 100644 --- a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml +++ b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-native-state - description: "Must use useNativeState from @expo/ui/jetpack-compose for native-shared state." + description: 'Must use useNativeState from @expo/ui/jetpack-compose for native-shared state.' - id: textfield-controlled - description: "Must wire the Expo UI TextField value and onValueChange to the native state value." + description: 'Must pass the native state object from useNativeState directly to the Expo UI TextField value prop.' - id: host-root - description: "Must render the Expo UI TextField under the Jetpack Compose Host." + description: 'Must render the Expo UI TextField under the Jetpack Compose Host.' - id: no-react-state-mirror - description: "Must hold the field value in native state, not a parallel React useState." + description: 'Must hold the field value in native state, not a parallel React useState.' diff --git a/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx index 9ab6140b..003317d6 100644 --- a/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx +++ b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx @@ -1,11 +1,19 @@ -import { Host as AndroidHost, Column as AndroidColumn, Text as AndroidText } from '@expo/ui/jetpack-compose' +import { + Host as AndroidHost, + Column as AndroidColumn, + Text as AndroidText, +} from '@expo/ui/jetpack-compose' import { background as androidBackground, clip as androidClip, shadow as androidShadow, Shapes, } from '@expo/ui/jetpack-compose/modifiers' -import { Host as IOSHost, Column as IOSColumn, Text as IOSText } from '@expo/ui/swift-ui' +import { + Host as IOSHost, + Text as IOSText, + VStack as IOSVStack, +} from '@expo/ui/swift-ui' import { background as iosBackground, cornerRadius as iosCornerRadius, @@ -18,7 +26,7 @@ export default function App() { return ( Featured - Weekly digest Your top stories, every Monday. - + ) } diff --git a/evals/tsconfig.expo.json b/evals/tsconfig.expo.json new file mode 100644 index 00000000..2dd6fa5e --- /dev/null +++ b/evals/tsconfig.expo.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "expo-router/**/*.ts", + "expo-router/**/*.tsx", + "expo-sdk/**/*.ts", + "expo-sdk/**/*.tsx", + "expo-ui/**/*.ts", + "expo-ui/**/*.tsx" + ], + "exclude": [ + // Pre-migration baseline for eval 01: it intentionally imports theming from + // '@react-navigation/native' (that is the eval's whole premise). That package's + // global ReactNavigation.Theme augmentation merges into this shared program and + // conflicts with expo-router's vendored theming types, breaking the idiomatic + // SDK 56 reference in the same program. The reference stays idiomatic; we exclude + // only the deliberately-legacy baseline file from the typecheck gate. + "expo-router/01-rn-expo-router-sdk56-react-navigation-imports/app/_layout.tsx" + ] +} diff --git a/package.json b/package.json index 9c612b0b..a43c1dc1 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "format": "prettier --write .", "bench:run": "bun runner/run.ts", "bench:judge": "bun runner/judge.ts", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "typecheck:expo-evals": "tsc -p evals/tsconfig.expo.json --noEmit" }, "devDependencies": { "@types/node": "^25.2.2", diff --git a/testbench/package.json b/testbench/package.json index 426008ba..aacc0c4e 100644 --- a/testbench/package.json +++ b/testbench/package.json @@ -15,6 +15,7 @@ }, "dependencies": { "@expo/ui": "~56.0.18", + "@gorhom/bottom-sheet": "^5.2.6", "@legendapp/list": "^3.0.0-beta.42", "@react-native-async-storage/async-storage": "2.2.0", "@react-native-community/netinfo": "^12.0.1", @@ -44,11 +45,13 @@ "expo-task-manager": "~56.0.19", "expo-updates": "~56.0.19", "expo-video": "~56.1.4", + "expo-video-thumbnails": "~56.0.3", "jotai": "^2.18.0", "react": "19.2.3", "react-native": "0.85.3", "react-native-gesture-handler": "~2.31.1", "react-native-keyboard-controller": "1.21.6", + "react-native-pager-view": "8.0.1", "react-native-reanimated": "4.3.1", "react-native-safe-area-context": "~5.7.0", "react-native-screens": "4.25.2", From d5ea484f3ae682a571d61ade52738a0cea40fa97 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 3 Jul 2026 11:00:10 +0400 Subject: [PATCH 27/32] fix(evals): make path-based requirements judgeable; second-pass eval polish - Include file paths in the judge prompt (mirrors the solver prompt), so placement/naming requirements (+not-found.tsx, docs/ catch-all scoping, tab trigger names) are gradeable from evidence - Keep expo-router/09 reference in the solver's flat path namespace and drop the out-of-app placement claim the harness cannot express - De-leak remaining prompts that named graded APIs (barcode scanner props, EAS projectId) - Drop expo-ui/04 requirements pre-satisfied by the baseline; scope the expo-ui/03 fallback requirement to platforms lacking the mode Co-Authored-By: Claude Fable 5 --- .../09-rn-expo-router-static-vs-server-loader/prompt.md | 2 +- .../reference/{app => }/_layout.tsx | 0 .../reference/{app => }/index.tsx | 0 .../reference/{app => }/profile.tsx | 2 +- .../03-rn-expo-camera-barcode-audio-config/prompt.md | 2 +- .../prompt.md | 2 +- .../requirements.yaml | 2 +- .../04-rn-expo-ui-pagerview-drop-in/requirements.yaml | 8 ++------ runner/evaluators/llm/prompt.ts | 3 ++- 9 files changed, 9 insertions(+), 12 deletions(-) rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/{app => }/_layout.tsx (100%) rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/{app => }/index.tsx (100%) rename evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/{app => }/profile.tsx (83%) diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md index 7be4cc96..8e90d5f1 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md @@ -1 +1 @@ -The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into a server-only module that lives outside the route directory (for example lib/profile.server.ts at the project root, so the router never treats it as a route) and expose it through a route loader that returns the profile name, then render the name in the client with useLoaderData so the secret never ships in the client bundle. +The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into a server-only module (for example lib/profile.server.ts) and expose it through a route loader that returns the profile name, then render the name in the client from the loader's data so the secret never ships in the client bundle. diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx similarity index 100% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/_layout.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/_layout.tsx diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/index.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx similarity index 100% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/index.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/index.tsx diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx similarity index 83% rename from evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx rename to evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx index b8666b51..d1dd6f29 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/app/profile.tsx +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx @@ -1,6 +1,6 @@ import { useLoaderData } from 'expo-router' import { Text } from 'react-native' -import { getProfile } from '../lib/profile.server' +import { getProfile } from './lib/profile.server' export async function loader() { return getProfile() diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md index d48ac355..7fe478dd 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md @@ -1 +1 @@ -Convert this scanner screen to a real expo-camera CameraView once camera permission is granted. Configure barcode scanning through the CameraView's barcodeScannerSettings with an explicit barcodeTypes allowlist of "qr" and "ean13" (not every type), and in the onBarcodeScanned handler ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. +Convert this scanner screen to a real expo-camera CameraView once camera permission is granted. Restrict scanning to an explicit allowlist so the camera only recognizes QR and EAN-13 codes (not every supported type), and ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. diff --git a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md index 588a3200..1a2a3635 100644 --- a/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md +++ b/evals/expo-sdk/09-rn-expo-notifications-android-channel-token/prompt.md @@ -1 +1 @@ -Wire up the Register button to obtain an Expo push token with expo-notifications. On Android, create the notification channel before requesting the token; gate the request behind granted notification permission; pass the EAS projectId; and render a deterministic error state if registration fails. +Wire up the Register button to obtain an Expo push token with expo-notifications. On Android, create the notification channel before requesting the token; gate the request behind granted notification permission; request the token explicitly for the app's EAS project rather than relying on defaults; and render a deterministic error state if registration fails. diff --git a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml index 4e632ec0..d492212d 100644 --- a/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml +++ b/evals/expo-ui/03-rn-expo-ui-datetimepicker-cross-platform/requirements.yaml @@ -14,4 +14,4 @@ requirements: - id: handles-dismissal-via-ondismiss description: 'Must handle the picker being dismissed without a selection via onDismiss, not by expecting an undefined date from onValueChange.' - id: platform-mode-fallback - description: 'Must render a visible text fallback for a date/time mode not available on the current platform.' + description: 'On platforms where a requested date/time mode is not available (such as the combined mode on Android), must render a visible text fallback.' diff --git a/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml index 463923ac..c5136de7 100644 --- a/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml +++ b/evals/expo-ui/04-rn-expo-ui-pagerview-drop-in/requirements.yaml @@ -4,10 +4,6 @@ inputs: - app/App.tsx requirements: - id: community-pagerview-import - description: "Must import PagerView from @expo/ui/community/pager-view." - - id: page-selected-state - description: "Must update state from onPageSelected native event position." - - id: stable-page-keys - description: "Must give each page stable keys." + description: 'Must import PagerView from @expo/ui/community/pager-view.' - id: no-react-native-pager-view-import - description: "Must not import react-native-pager-view directly." + description: 'Must not import react-native-pager-view directly.' diff --git a/runner/evaluators/llm/prompt.ts b/runner/evaluators/llm/prompt.ts index 78ec4d17..885585a8 100644 --- a/runner/evaluators/llm/prompt.ts +++ b/runner/evaluators/llm/prompt.ts @@ -23,7 +23,7 @@ export function buildJudgePrompt( const filesBlock = files .map((file) => { return ` - + ${file.content} ` @@ -36,6 +36,7 @@ export function buildJudgePrompt( Rules: - Use only the submitted files as evidence. + - File paths are part of the submission and may be used as evidence for placement and naming requirements. - Return exactly one result per declared requirement id. - Mark passed=false if evidence is missing or contradictory. - Keep reasons concise, concrete, and technically specific. From 3521c921a7860aca0de9a110cfc270664ced8726 Mon Sep 17 00:00:00 2001 From: Mike Grabowski Date: Fri, 3 Jul 2026 11:29:29 +0400 Subject: [PATCH 28/32] fix(evals): ground references in package implementation; enforce guard and leak policies Implementation-verified fixes across all three expo categories: - SuspenseFallback moved to the layout route (leaf-route exports are ignored by expo-router in sync import mode) - Remove player.pause() from unmount cleanups (useReleasingSharedObject releases the player before the component cleanup runs, so the call throws); pause stays AppState-driven - Wrap multi-child Host content in Column/VStack (Host lays out direct children as an overlapping stack on both platforms) - Idempotent re-download into Paths.cache; drop dead videoMaxDuration; drop deprecated addVisibilityListener and unprompted reloadScreenOptions grading; make headerBackTitle observable via a second screen - Guard policy: at most one baseline-passable requirement per eval, kept only for documented deprecations or preserve-constraints; the rest rebound to the migrated surface or deleted - Leak policy: prompts may name the source package being migrated from but never the graded target identifiers; de-leaked remaining prompts - Escape solver-controlled paths in the judge prompt attribute and add buildJudgePrompt tests Co-Authored-By: Claude Fable 5 --- .../app/_layout.tsx | 1 + .../app/details.tsx | 14 ++++++ .../app/index.tsx | 2 + .../prompt.md | 2 +- .../reference/_layout.tsx | 7 ++- .../reference/details.tsx | 14 ++++++ .../reference/index.tsx | 2 + .../requirements.yaml | 13 +++--- .../requirements.yaml | 12 ++--- .../requirements.yaml | 10 ++--- .../prompt.md | 2 +- .../reference/_layout.tsx | 5 +++ .../reference/index.tsx | 6 +-- .../requirements.yaml | 8 ++-- .../prompt.md | 2 +- .../prompt.md | 2 +- .../requirements.yaml | 10 ++--- .../prompt.md | 2 +- .../requirements.yaml | 10 ++--- .../reference/App.tsx | 1 - .../prompt.md | 2 +- .../requirements.yaml | 4 +- .../requirements.yaml | 10 ++--- .../prompt.md | 2 +- .../prompt.md | 2 +- .../prompt.md | 2 +- .../reference/App.tsx | 3 +- .../requirements.yaml | 10 ++--- .../prompt.md | 2 +- .../requirements.yaml | 8 ++-- .../prompt.md | 2 +- .../reference/App.tsx | 7 ++- .../requirements.yaml | 10 ++--- .../20-rn-expo-video-player-view/prompt.md | 2 +- .../reference/App.tsx | 1 - .../requirements.yaml | 10 ++--- .../reference/App.tsx | 11 ++--- .../requirements.yaml | 10 ++--- .../requirements.yaml | 8 ++-- .../prompt.md | 2 +- .../reference/App.tsx | 13 +----- .../requirements.yaml | 14 +++--- .../requirements.yaml | 10 ++--- .../requirements.yaml | 6 +-- .../requirements.yaml | 8 ++-- .../requirements.yaml | 2 - .../app/App.tsx | 4 +- .../reference/App.tsx | 14 ++++-- .../reference/App.tsx | 44 ++++++++++--------- runner/evaluators/llm/prompt.ts | 19 +++++++- runner/evaluators/llm/tests/prompt.test.ts | 34 ++++++++++++++ 51 files changed, 239 insertions(+), 162 deletions(-) create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/app/details.tsx create mode 100644 evals/expo-router/03-rn-expo-router-stack-composition-header/reference/details.tsx create mode 100644 runner/evaluators/llm/tests/prompt.test.ts diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx index 9b13dcb9..da2587e1 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/_layout.tsx @@ -4,6 +4,7 @@ export default function Layout() { return ( + ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/details.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/details.tsx new file mode 100644 index 00000000..c87fe53a --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/details.tsx @@ -0,0 +1,14 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Details() { + return ( + + Details + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx index a5bf2cf3..ea6b7a94 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/app/index.tsx @@ -1,3 +1,4 @@ +import { Link } from 'expo-router' import { StyleSheet, Text, View } from 'react-native' export default function Index() { @@ -5,6 +6,7 @@ export default function Index() { Inbox Tap the header action to add a new item. + Open details ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md index 0b14ca46..abea4f8b 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md @@ -1 +1 @@ -Configure the Inbox screen header in the Stack layout: set the title, a back button label, and a right-side header button that shows an alert when pressed. \ No newline at end of file +In the Stack layout, configure the Inbox (index) screen header: set its title and a right-side header button that shows an alert when pressed. There is also a Details screen pushed from the Inbox. Configure the Details screen so that when it is open, its back button reads "Inbox" instead of the default label. diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx index aa15f844..aa8a352c 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx @@ -8,7 +8,6 @@ export default function Layout() { name="index" options={{ title: 'Inbox', - headerBackTitle: 'Back', headerRight: () => ( Alert.alert('New item')}> + @@ -16,6 +15,12 @@ export default function Layout() { ), }} /> + ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/details.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/details.tsx new file mode 100644 index 00000000..c87fe53a --- /dev/null +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/details.tsx @@ -0,0 +1,14 @@ +import { StyleSheet, Text, View } from 'react-native' + +export default function Details() { + return ( + + Details + + ) +} + +const styles = StyleSheet.create({ + container: { flex: 1, gap: 12, padding: 24 }, + title: { fontSize: 20, fontWeight: '600' }, +}) diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx index a5bf2cf3..ea6b7a94 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/index.tsx @@ -1,3 +1,4 @@ +import { Link } from 'expo-router' import { StyleSheet, Text, View } from 'react-native' export default function Index() { @@ -5,6 +6,7 @@ export default function Index() { Inbox Tap the header action to add a new item. + Open details ) } diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml index 54495fbd..50a1cb7a 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml @@ -3,12 +3,15 @@ inputs: files: - app/_layout.tsx - app/index.tsx + - app/details.tsx requirements: - id: uses-stack-screen-options-for-header - description: "Must configure the header via Stack.Screen options (title/headerRight), not Stack.Toolbar." + description: 'Must configure the header via Stack.Screen options (title/headerRight), not Stack.Toolbar.' - id: header-right-shows-alert - description: "The headerRight must render a pressable button whose press handler calls Alert.alert." - - id: sets-title-and-back-button - description: "Must set the screen title and a back button label via headerBackTitle in the Stack.Screen options." + description: 'The index (Inbox) screen headerRight must render a pressable button whose press handler calls Alert.alert.' + - id: sets-inbox-title + description: 'Must set the index (Inbox) screen title via its Stack.Screen options.' + - id: sets-details-back-title + description: "Must set headerBackTitle in the details screen's Stack.Screen options so the back button on the pushed details screen shows the custom label; setting headerBackTitle on the index screen would not affect the back button." - id: no-react-navigation-header-imports - description: "Must not import React Navigation header components or types directly." + description: 'Must not import React Navigation header components or types directly.' diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml index 23ee09e5..48c3ef82 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -8,9 +8,11 @@ inputs: requirements: - id: uses-stack-protected description: 'Must gate routes with Stack.Protected, since the app uses a Stack layout.' - - id: signed-out-fallback - description: 'The layout must keep an unguarded, always-available route (such as index or the signed-out sign-in screen) declared so signed-out users deterministically land somewhere instead of a guarded screen.' + - id: account-guarded-signed-in + description: 'The account screen must be wrapped so it is only present when signedIn is true.' + - id: sign-in-guarded-signed-out + description: 'The sign-in screen must be wrapped so it is only present when signedIn is false.' - id: guard-boolean-explicit - description: 'Must pass explicit guard booleans derived from auth state.' - - id: no-redirect-loop - description: 'Must avoid unconditional redirects that can loop between protected and sign-in routes.' + description: 'Must pass explicit guard booleans derived from auth state to Stack.Protected.' + - id: signed-out-fallback + description: 'The layout must keep an unguarded, always-available route (such as index) declared so signed-out users deterministically land somewhere instead of every route being guarded away.' diff --git a/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml index c7c49800..2970a723 100644 --- a/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml +++ b/evals/expo-router/08-rn-expo-router-serializable-search-params/requirements.yaml @@ -5,11 +5,11 @@ inputs: - app/index.tsx - app/details.tsx requirements: - - id: serializable-link-params - description: "Must navigate with serializable primitive search params." + - id: link-carries-id-and-tab + description: 'The Open details link must carry both the product id and the selected tab (from the PRODUCT constant) as route params to the details screen.' - id: uses-local-search-params - description: "Must read route params with useLocalSearchParams or useGlobalSearchParams from expo-router." + description: 'Must read route params with useLocalSearchParams or useGlobalSearchParams from expo-router.' - id: param-fallbacks - description: "Must handle missing params with fallback values." + description: 'Must handle missing params (e.g. a direct deep link) with fallback values instead of rendering blanks.' - id: no-object-function-params - description: "Must not pass functions, class instances, or non-serializable objects as route params." + description: 'Must not pass functions, class instances, or non-serializable objects as route params; the carried params must be serializable primitives.' diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md index 0218c12c..51dd5fb6 100644 --- a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/prompt.md @@ -1 +1 @@ -The index route renders async content with React Suspense. Show a "Loading…" indicator while the content resolves, implemented at the route level rather than through a global wrapper, and keep the route's default export rendering the resolved content. +The index route renders async content with React Suspense. Show a "Loading…" indicator while the content resolves, wired into expo-router's own routing layer so child routes fall back to it (rather than a global wrapper you mount yourself), and keep the index route's default export rendering the resolved content. diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx index 99996670..20887f07 100644 --- a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/_layout.tsx @@ -1,4 +1,9 @@ import { Stack } from 'expo-router' +import { Text } from 'react-native' + +export function SuspenseFallback() { + return Loading route... +} export default function Layout() { return diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx index 3287f765..a76247fc 100644 --- a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/reference/index.tsx @@ -2,13 +2,9 @@ import { use } from 'react' import { Text, View } from 'react-native' const contentPromise = new Promise((resolve) => - setTimeout(() => resolve('Async route content'), 500), + setTimeout(() => resolve('Async route content'), 500) ) -export function SuspenseFallback() { - return Loading route... -} - export default function Index() { const content = use(contentPromise) diff --git a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml index 66fe860b..4008bf3b 100644 --- a/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml +++ b/evals/expo-router/10-rn-expo-router-suspense-fallback-layout/requirements.yaml @@ -5,10 +5,8 @@ inputs: - app/index.tsx requirements: - id: uses-suspense-fallback - description: "Must export a route-level SuspenseFallback function from the route module." + description: 'Must export a SuspenseFallback function from the layout route (app/_layout.tsx) so descendant routes suspend into it; a SuspenseFallback exported from a leaf route module is ignored by expo-router in sync import mode.' - id: fallback-renders-loading-indicator - description: "SuspenseFallback must render a visible loading indicator (for example a Text reading \"Loading…\") while the async route content is pending." + description: 'SuspenseFallback must render a visible loading indicator (for example a Text reading "Loading…") while the async route content is pending.' - id: default-export-renders-async-content - description: "Must keep the route's default export rendering the resolved async content." - - id: no-global-loading-hack - description: "Must not replace the route content with a permanent loading screen that never shows the resolved content." + description: "Must keep the index route's default export rendering the resolved async content, not replace it with a permanent loading screen that never shows the resolved content." diff --git a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md index 6f9ae0e9..3e4e3b20 100644 --- a/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md +++ b/evals/expo-sdk/01-rn-expo-camera-permission-denied-retry/prompt.md @@ -1 +1 @@ -Wire this camera screen up to expo-camera. Request camera permission only when the user taps "Enable Camera" (never on mount), and guard against overlapping prompts while a request is already in flight. Render CameraView in the preview area only once permission is granted, and keep the "Camera is off" fallback for every other state. When access is permanently blocked and the app can no longer prompt, show the Settings recovery block and take the user to the system settings instead of prompting again. Re-check the permission whenever the app returns to the foreground so a grant made in Settings is picked up. +Wire this camera screen up to expo-camera. Request camera permission only when the user taps "Enable Camera" (never on mount), and guard against overlapping prompts while a request is already in flight. Render the live camera preview in the preview area only once permission is granted, and keep the "Camera is off" fallback for every other state. When access is permanently blocked and the app can no longer prompt, show the Settings recovery block and take the user to the system settings instead of prompting again. Re-check the permission whenever the app returns to the foreground so a grant made in Settings is picked up. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md index 68bd5c89..573c80ad 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md @@ -1 +1 @@ -Convert this preview screen to use a real expo-camera CameraView. Drive CameraView's active prop from a combination of the app being in the foreground (listen to AppState and set it false whenever the app leaves the active state) and the existing "Camera enabled" switch, so backgrounding the app or flipping the switch pauses the preview without tearing down permission state. When camera permission is not granted, do not render CameraView at all — show the paused/fallback text instead. Remove the AppState listener when the component unmounts. +Convert this preview screen to use a real expo-camera preview. The live preview must pause — without tearing down or remounting the camera view or losing permission state — whenever the app leaves the foreground or the user turns the "Camera enabled" switch off, and resume only once the app is foregrounded again and the switch is back on. When camera permission is not granted, do not mount the camera preview at all — show the paused/fallback text instead. Clean up any listeners you register when the component unmounts. diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml index a6c54ea2..5f529c82 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml +++ b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: camera-active-derived-from-visibility - description: "Must pass CameraView an active prop derived from AppState foreground state and the user-enabled preview switch." + description: 'Must pass CameraView an active prop derived from AppState foreground state and the user-enabled preview switch.' - id: camera-appstate-background-pauses - description: "Must listen to AppState and set active false when the app leaves the active state." + description: 'Must listen to AppState and set active false when the app leaves the active state.' - id: camera-view-unmounted-without-permission - description: "Must not render CameraView at all when camera permission is not granted." + description: 'Must not render CameraView at all when camera permission is not granted.' - id: manual-preview-toggle - description: "Must expose a user action that toggles the preview without losing permission state." + description: "Must feed the 'Camera enabled' switch into the CameraView active prop so toggling it pauses/resumes the preview without losing permission state." - id: cleanup-appstate-subscription - description: "Must remove the AppState listener on unmount." + description: 'Must remove the AppState listener on unmount.' diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md index 7fe478dd..c358ef42 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md @@ -1 +1 @@ -Convert this scanner screen to a real expo-camera CameraView once camera permission is granted. Restrict scanning to an explicit allowlist so the camera only recognizes QR and EAN-13 codes (not every supported type), and ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. +Convert this scanner screen to a real expo-camera preview once camera permission is granted. Restrict scanning to an explicit allowlist so the camera only recognizes QR and EAN-13 codes (not every supported type), and ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml index e2b93f1a..a8a13365 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: uses-current-canceled-spelling - description: "Must check result.canceled, not the old result.cancelled spelling." + description: 'Must check result.canceled, not the old result.cancelled spelling.' - id: assets-null-guard - description: "Must guard result.assets before indexing because canceled results have assets: null." + description: 'Must guard result.assets before indexing because canceled results have assets: null.' - id: no-launch-on-mount - description: "Must call launchImageLibraryAsync only from a user action." + description: 'Must call launchImageLibraryAsync only from a user action.' - id: uses-current-media-types-array - description: "Must use the current MediaType array form such as mediaTypes: [\"images\"] rather than depending on deprecated MediaTypeOptions." + description: 'Must use the current MediaType array form such as mediaTypes: ["images"] rather than depending on deprecated MediaTypeOptions.' - id: renders-empty-state - description: "Must show a stable empty/canceled UI path without crashing when the user cancels." + description: 'Must keep the preview in its empty state from the picker-cancellation branch (the result.canceled path) without crashing, rather than relying only on the static initial fallback.' diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx index b7b2cb96..2180b0a2 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx @@ -27,7 +27,6 @@ export default function App() { ) const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['videos'], - videoMaxDuration: 60, }) const asset = !result.canceled && result.assets?.[0]?.type === 'video' diff --git a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md index 8239b3f6..853bec89 100644 --- a/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md +++ b/evals/expo-sdk/07-rn-expo-location-background-foreground-first/prompt.md @@ -1 +1 @@ -Wire up the Track in background switch. When turned on, request foreground location permission first and then background permission, and start background location updates only after both are granted; when turned off, stop the updates. Define the TaskManager task once and avoid starting duplicate updates. +Wire up the Track in background switch. When turned on, request foreground location permission first and then background permission, and start background location updates only after both are granted; when turned off, stop the updates. Register the background location task a single time so it is not redefined on every render, and avoid starting duplicate updates when tracking is already running. diff --git a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml index 07ce8357..0036d02d 100644 --- a/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml +++ b/evals/expo-sdk/08-rn-expo-location-accuracy-authorization/requirements.yaml @@ -6,8 +6,8 @@ requirements: - id: uses-location-permission-details description: 'Must inspect platform permission details such as permission.ios?.accuracy or permission.android?.accuracy when present.' - id: does-not-assume-precise-location - description: 'Must not assume granted permission implies precise/exact location accuracy.' + description: 'Must derive precise vs approximate from the permission response accuracy fields (ios full/reduced or android fine/coarse) rather than a hardcoded flag, so a granted permission is not assumed precise.' - id: fallback-for-approximate - description: 'Must render a specific approximate-location fallback or explanation.' + description: 'Must render the approximate-location explanation driven by that derived approximate state, not by an unconditional/static value.' - id: settings-recovery-for-blocked description: 'Must offer Linking.openSettings() when permission canAskAgain is false.' diff --git a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml index faeab568..c124e601 100644 --- a/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml +++ b/evals/expo-sdk/10-rn-expo-notifications-listener-cleanup/requirements.yaml @@ -4,12 +4,10 @@ inputs: - app/App.tsx requirements: - id: received-listener-registered - description: "Must register addNotificationReceivedListener in a mount effect." + description: 'Must register addNotificationReceivedListener in a mount effect.' - id: response-listener-registered - description: "Must register addNotificationResponseReceivedListener in the same component lifecycle." + description: 'Must register addNotificationResponseReceivedListener in the same component lifecycle.' - id: subscriptions-removed - description: "Must call remove() on every notification subscription in the effect cleanup." + description: 'Must call remove() on every notification subscription in the effect cleanup.' - id: state-update-from-listeners - description: "Must update visible local state from both received notification and response listener payloads." - - id: no-remove-all-listeners - description: "Must not use removeAllListeners as cleanup for component-scoped subscriptions." + description: 'Must update visible local state from both received notification and response listener payloads.' diff --git a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md index bbc74635..69301d03 100644 --- a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md +++ b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/prompt.md @@ -1 +1 @@ -Wire up the notes screen's save and load using the expo-file-system object API (File/Directory/Paths). Persist the text to a cache file, create the directory idempotently, and on first run (no file yet) load fallback text instead of crashing. +Wire up the notes screen's save and load using the SDK 56 object-based file API from expo-file-system. Persist the text to a cache file, create the directory idempotently, and on first run (no file yet) load fallback text instead of crashing. diff --git a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md index 21919412..b5d737de 100644 --- a/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md +++ b/evals/expo-sdk/13-rn-expo-filesystem-legacy-root-methods/prompt.md @@ -1 +1 @@ -Migrate the profile file helper off the legacy expo-file-system API to the SDK 56 object API (Directory, File, Paths). Keep the save/load behavior identical. +Migrate the profile file helper off the legacy expo-file-system API to the SDK 56 object-based file API. Keep the save/load behavior identical. diff --git a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md index 8661fdbd..e1f4d1d6 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md +++ b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/prompt.md @@ -1 +1 @@ -Wire up the sync flow: download the remote file into a local cache directory while showing download progress, then upload it to the server endpoint. Use the expo-file-system object API for the download and a web-compatible upload (fetch/FormData), and render a deterministic failure state on error. +Wire up the sync flow: download the remote file into a local cache directory while showing download progress, then upload it to the server endpoint. Use the expo-file-system object API for the download and a web-compatible multipart upload that works without the legacy native upload helper, and render a deterministic failure state on error. diff --git a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx index 622b701d..eaa8a366 100644 --- a/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx +++ b/evals/expo-sdk/14-rn-expo-filesystem-download-upload/reference/App.tsx @@ -21,9 +21,10 @@ export default function App() { setPhase('downloading') setProgress(0) try { - const downloads = new Directory(Paths.document, 'downloads') + const downloads = new Directory(Paths.cache, 'downloads') downloads.create({ idempotent: true, intermediates: true }) const file = await File.downloadFileAsync(REMOTE_URL, downloads, { + idempotent: true, onProgress: ({ bytesWritten, totalBytes }) => { if (totalBytes > 0) { setProgress(bytesWritten / totalBytes) diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml index 42e90cb6..75f7a431 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: write-only-permission-request - description: "Must call MediaLibrary.requestPermissionsAsync with writeOnly true for save-only behavior." + description: 'Must call MediaLibrary.requestPermissionsAsync with writeOnly true for save-only behavior.' - id: granular-photo-permission - description: "Must pass granularPermissions containing photo when requesting photo-only access." - - id: does-not-query-library-with-writeonly - description: "Must not query/read the user library after requesting write-only permission." + description: 'Must pass granularPermissions containing photo when requesting photo-only access.' + - id: saves-image-via-write-path + description: 'Must save the generated image to the library through a write/save path (such as Asset.create) once write-only permission is granted.' - id: denied-fallback - description: "Must render a deterministic denied-permission fallback." + description: 'Must render a deterministic denied-permission fallback.' diff --git a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md index dd9d3731..12e28a8a 100644 --- a/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md +++ b/evals/expo-sdk/16-rn-expo-media-library-file-asset-create/prompt.md @@ -1 +1 @@ -Wire up the Save button to save the generated image to the media library and add it to an album, using the current expo-media-library class APIs (Asset/Album). Check permission and confirm the file exists before creating the asset. +Wire up the Save button to save the generated image to the media library and add it to an album, using the current class-based expo-media-library API. Check permission and confirm the file exists before creating the asset. diff --git a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml index 3eb6c438..c76c0cab 100644 --- a/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml +++ b/evals/expo-sdk/18-rn-expo-contacts-config-fields-query/requirements.yaml @@ -4,10 +4,8 @@ inputs: - app/App.tsx requirements: - id: permission-before-query - description: "Must request contacts permission before calling Contacts.Contact.getAllDetails or another current Contact class query API." + description: 'Must request contacts permission before calling Contacts.Contact.getAllDetails or another current Contact class query API.' - id: field-allowlist - description: "Must pass a ContactField allowlist that includes only the rendered fields, such as FULL_NAME, EMAILS, and IMAGE." - - id: empty-list-fallback - description: "Must handle an empty data array with deterministic fallback UI." + description: 'Must pass a ContactField allowlist that includes only the rendered fields, such as FULL_NAME, EMAILS, and IMAGE.' - id: no-query-on-mount-permission-prompt - description: "Must not prompt for contacts permission on initial mount." + description: 'Must not prompt for contacts permission on initial mount; the permission request must run only inside the button press handler.' diff --git a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md index 2bc57937..d7a2a0b0 100644 --- a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md +++ b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/prompt.md @@ -1 +1 @@ -Wire up the audio preview to play a sound file and show its playback status using the current Expo audio APIs (expo-audio, not expo-av). Configure the audio mode deliberately, and pause playback when the app is backgrounded or the component unmounts. +Wire up the audio preview to play a sound file and show its playback status using the current SDK 56 audio API (expo-av is deprecated). Configure the audio mode deliberately, and pause playback when the app is backgrounded. diff --git a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx index 4c11a331..2c4a43c6 100644 --- a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx +++ b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/reference/App.tsx @@ -1,4 +1,8 @@ -import { setAudioModeAsync, useAudioPlayer, useAudioPlayerStatus } from 'expo-audio' +import { + setAudioModeAsync, + useAudioPlayer, + useAudioPlayerStatus, +} from 'expo-audio' import { useEffect } from 'react' import { AppState, Pressable, StyleSheet, Text, View } from 'react-native' @@ -18,7 +22,6 @@ export default function App() { if (state !== 'active') player.pause() }) return () => { - player.pause() subscription.remove() } }, [player]) diff --git a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml index 380c52dd..c3a6b080 100644 --- a/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml +++ b/evals/expo-sdk/19-rn-expo-audio-player-lifecycle/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: uses-expo-audio - description: "Must import playback APIs from expo-audio and not from expo-av." + description: 'Must import playback APIs from the current SDK 56 audio module and not from the deprecated expo-av package.' - id: uses-managed-player-hook - description: "Must use useAudioPlayer for component-managed player lifecycle." + description: 'Must use useAudioPlayer for component-managed player lifecycle.' - id: uses-player-status-hook - description: "Must use useAudioPlayerStatus or an equivalent current status subscription for UI state." + description: 'Must use useAudioPlayerStatus or an equivalent current status subscription for UI state.' - id: audio-mode-explicit - description: "Must call setAudioModeAsync with deliberate playback/interruption options." + description: 'Must call setAudioModeAsync with deliberate playback/interruption options.' - id: pause-or-stop-on-background - description: "Must pause playback when AppState leaves active or the component unmounts." + description: 'Must pause playback when AppState leaves active and remove the AppState subscription in the effect cleanup.' diff --git a/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md b/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md index 243f5da6..22d4dea8 100644 --- a/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md +++ b/evals/expo-sdk/20-rn-expo-video-player-view/prompt.md @@ -1 +1 @@ -Wire up the video player to play a video URL with looping and mute controls using the current Expo video APIs (expo-video, not expo-av). Pause or avoid autoplay when the app is backgrounded or the view is not visible. +Wire up the video player to play a video URL with looping and mute controls using the current SDK 56 video API (expo-av is deprecated). Pause playback when the app is backgrounded. diff --git a/evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx b/evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx index 035f8f22..fa52d3d7 100644 --- a/evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx +++ b/evals/expo-sdk/20-rn-expo-video-player-view/reference/App.tsx @@ -26,7 +26,6 @@ export default function App() { if (state !== 'active') player.pause() }) return () => { - player.pause() subscription.remove() } }, [player]) diff --git a/evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml b/evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml index 45e9f6cb..0ace2ac2 100644 --- a/evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml +++ b/evals/expo-sdk/20-rn-expo-video-player-view/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: uses-expo-video - description: "Must import VideoView and useVideoPlayer from expo-video." + description: 'Must import VideoView and useVideoPlayer from expo-video.' - id: no-expo-av-video - description: "Must not import Video or playback APIs from expo-av." + description: 'Must not import Video or playback APIs from expo-av.' - id: player-created-with-hook - description: "Must create the player with useVideoPlayer and configure looping/muted/playback in the setup callback or player API." + description: 'Must create the player with useVideoPlayer and configure looping/muted/playback in the setup callback or player API.' - id: videoview-receives-player - description: "Must pass the player object to VideoView." + description: 'Must pass the player object to VideoView.' - id: visibility-lifecycle - description: "Must pause or avoid autoplay when the app is backgrounded or the view is not active." + description: 'Must pause playback when AppState leaves active and remove the AppState subscription in the effect cleanup.' diff --git a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx index 8e797144..0613860c 100644 --- a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx +++ b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx @@ -18,7 +18,9 @@ export default function App() { downloadError, } = Updates.useUpdates() const [status, setStatus] = useState( - currentlyRunning.isEmbeddedLaunch ? 'Running embedded build.' : 'Up to date.', + currentlyRunning.isEmbeddedLaunch + ? 'Running embedded build.' + : 'Up to date.' ) const checkForUpdate = async () => { @@ -31,12 +33,7 @@ export default function App() { } setStatus('Downloading…') await Updates.fetchUpdateAsync() - await Updates.reloadAsync({ - reloadScreenOptions: { - backgroundColor: '#111827', - fade: true, - }, - }) + await Updates.reloadAsync() // Execution does not reliably continue after reloadAsync resolves. } catch (error) { setStatus(error instanceof Error ? error.message : 'Update failed.') diff --git a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml index 2b0876a7..8b99e821 100644 --- a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml +++ b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml @@ -4,12 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-useupdates-state - description: "Must use Updates.useUpdates() to read isDownloading, downloadProgress, isUpdateAvailable, isUpdatePending, and currentlyRunning state." + description: 'Must use Updates.useUpdates() to read isDownloading, downloadProgress, isUpdateAvailable, isUpdatePending, and currentlyRunning state.' - id: download-progress-rendered - description: "Must render downloadProgress or a deterministic progress state while downloading." - - id: reload-screen-options - description: "Must call Updates.reloadAsync with reloadScreenOptions when applying a downloaded update." + description: 'Must render downloadProgress or a deterministic progress state while downloading.' - id: no-post-reload-assumption - description: "Must not update React state after awaiting reloadAsync as if execution will reliably continue." + description: 'Must not update React state after awaiting reloadAsync as if execution will reliably continue.' - id: handles-disabled-or-error - description: "Must render a fallback for unavailable updates or download errors." + description: 'Must render a fallback for unavailable updates or download errors.' diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml index 5fb748a3..805da14f 100644 --- a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-header-override-api - description: "Must call Updates.setUpdateRequestHeadersOverride with a record or null." + description: 'Must call Updates.setUpdateRequestHeadersOverride with a record or null.' - id: clear-override-path - description: "Must provide a default path that calls setUpdateRequestHeadersOverride(null)." + description: 'Must provide a default path that calls setUpdateRequestHeadersOverride(null).' - id: check-after-header-change - description: "Must trigger or expose an update check/fetch flow after changing headers." + description: 'Must trigger or expose an update check/fetch flow after changing headers.' - id: visible-selected-cohort - description: "Must render the active channel/header selection so behavior is auditable." + description: 'Must render the currently selected channel that drives the header override so the active selection is auditable.' diff --git a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md index e1153db7..3b83b3b7 100644 --- a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md +++ b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/prompt.md @@ -1 +1 @@ -Wire up the appearance screen's controls to set the system status bar and navigation bar style, and to toggle a Liquid Glass surface when the platform supports it. Guard Android-only navigation bar calls, remove any visibility listener on cleanup, and restore the default bars on unmount. +Wire up the appearance screen's controls to set the system status bar and navigation bar style, and to toggle a Liquid Glass surface when the platform supports it. Guard Android-only navigation bar calls, and restore the default bars on unmount. diff --git a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx index b62e14b2..513ca50c 100644 --- a/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx +++ b/evals/expo-sdk/24-rn-expo-status-navigation-bar-current-api/reference/App.tsx @@ -1,5 +1,5 @@ import { GlassView, isGlassEffectAPIAvailable } from 'expo-glass-effect' -import { NavigationBar, addVisibilityListener } from 'expo-navigation-bar' +import { NavigationBar } from 'expo-navigation-bar' import { StatusBar } from 'expo-status-bar' import { useEffect, useState } from 'react' import { Platform, Pressable, StyleSheet, Text, View } from 'react-native' @@ -9,9 +9,6 @@ type BarStyle = 'light' | 'dark' export default function App() { const [barStyle, setBarStyle] = useState('dark') const [glass, setGlass] = useState(false) - const [navVisibility, setNavVisibility] = useState<'visible' | 'hidden'>( - 'visible', - ) const canUseGlass = isGlassEffectAPIAvailable() useEffect(() => { @@ -22,11 +19,7 @@ export default function App() { } } NavigationBar.setStyle(barStyle) - const subscription = addVisibilityListener((event) => { - setNavVisibility(event.visibility) - }) return () => { - subscription.remove() StatusBar.setStyle('auto', true) NavigationBar.setStyle('auto') } @@ -38,10 +31,6 @@ export default function App() { {Platform.OS === 'android' ? : null} Appearance - {Platform.OS === 'android' ? ( - Navigation bar: {navVisibility} - ) : null} - - - {query ? `Searching for "${query}"` : 'Start typing above'} - + Start typing above ) } diff --git a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx index ec43048a..11d5fe67 100644 --- a/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx +++ b/evals/expo-ui/06-rn-expo-ui-native-state-text-input/reference/App.tsx @@ -1,12 +1,20 @@ -import { Host, Text, TextField, useNativeState } from '@expo/ui/jetpack-compose' +import { + Column, + Host, + Text, + TextField, + useNativeState, +} from '@expo/ui/jetpack-compose' export default function App() { const query = useNativeState('') return ( - Search - + + Search + + ) } diff --git a/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx index 003317d6..e140075f 100644 --- a/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx +++ b/evals/expo-ui/07-rn-expo-ui-platform-modifier-escape-hatch/reference/App.tsx @@ -25,16 +25,18 @@ export default function App() { if (Platform.OS === 'ios') { return ( - Featured - - Weekly digest - Your top stories, every Monday. + + Featured + + Weekly digest + Your top stories, every Monday. + ) @@ -42,16 +44,18 @@ export default function App() { return ( - Featured - - Weekly digest - Your top stories, every Monday. + + Featured + + Weekly digest + Your top stories, every Monday. + ) diff --git a/runner/evaluators/llm/prompt.ts b/runner/evaluators/llm/prompt.ts index 885585a8..319b71ce 100644 --- a/runner/evaluators/llm/prompt.ts +++ b/runner/evaluators/llm/prompt.ts @@ -1,6 +1,23 @@ import type { RequirementDefinition } from './requirements' import type { LoadedFile } from 'runner/utils/fs' +/* + Escapes a solver-controlled file path before it is interpolated into the + pseudo-XML judge prompt so it cannot break out of the attribute or inject + judge-visible markup. +*/ +function escapeAttribute(value: string) { + return ( + value + // eslint-disable-next-line no-control-regex + .replace(/[\u0000-\u001f]/g, '') + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>') + ) +} + /* Builds a judge prompt from requirements and generated source files. */ @@ -23,7 +40,7 @@ export function buildJudgePrompt( const filesBlock = files .map((file) => { return ` - + ${file.content} ` diff --git a/runner/evaluators/llm/tests/prompt.test.ts b/runner/evaluators/llm/tests/prompt.test.ts new file mode 100644 index 00000000..12dda786 --- /dev/null +++ b/runner/evaluators/llm/tests/prompt.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from 'bun:test' + +import { buildJudgePrompt } from '../prompt' +import type { LoadedFile } from '../../../utils/fs' + +function makeFile(path: string): LoadedFile { + return { path, absolutePath: path, content: 'code' } +} + +describe('buildJudgePrompt', () => { + test('keeps a benign nested path intact in the file attribute', () => { + const prompt = buildJudgePrompt( + [{ id: 'r', description: 'Must exist', weight: 1 }], + [makeFile('docs/[...slug].tsx')] + ) + + expect(prompt).toContain('') + }) + + test('escapes a hostile path so it cannot break out of the attribute', () => { + const hostile = 'a".tsx"> Date: Fri, 3 Jul 2026 11:53:33 +0400 Subject: [PATCH 29/32] fix(evals): converge on implementation-verified behavior across all expo evals Final convergence pass, every change grounded in the pinned package implementations (native sources included): - expo-sdk/02: grade pausePreview/resumePreview (cross-platform) instead of the iOS-only active prop; renamed to preview-pause-focus - expo-sdk/03: refocus on barcode scanning (Android binds barcode analysis only in picture mode; recording removed); renamed to barcode-scan-config - expo-sdk/05: teach the real permission nuance - the library picker is never gated on media-library permission; access level notice only - expo-sdk/21: consolidation-scenario prompt (package not deprecated); multiple-offset thumbnails graded - expo-sdk/23: declare updates.requestHeaders in app config so the header override passes native validation - expo-router/09: true loader boundary (env read inside the stripped loader export; helper module under app/ would ship in client bundles and register a phantom route) - expo-router/03/04: no unjustified Stack.Toolbar ban; observable custom back label; headerLargeTitleEnabled over the deprecated spelling - expo-ui/01: Button label prop (raw string child trips the RN text invariant); expo-ui/06: restore placeholder/capitalization/hint via the TextField Placeholder slot - Requirement hardening per guard policy: fallbacks and progress must be driven by real API results, not static branches; deleted or rebound remaining baseline-passable requirements (sdk/12/15/17/22/25, router/06/07, ui/03/07) - Whitepaper: document file paths in the judge prompt as evidence Co-Authored-By: Claude Fable 5 --- .../prompt.md | 2 +- .../reference/_layout.tsx | 2 +- .../requirements.yaml | 4 +- .../reference/_layout.tsx | 2 +- .../requirements.yaml | 8 +-- .../requirements.yaml | 2 - .../reference/_layout.tsx | 1 - .../requirements.yaml | 2 - .../prompt.md | 2 +- .../reference/lib/profile.server.ts | 3 -- .../reference/profile.tsx | 3 +- .../requirements.yaml | 2 +- .../requirements.yaml | 15 ------ .../app/App.tsx | 0 .../prompt.md | 0 .../reference/App.tsx | 17 +++++-- .../requirements.yaml | 15 ++++++ .../prompt.md | 1 - .../requirements.yaml | 15 ------ .../app/App.tsx | 23 ++------- .../prompt.md | 1 + .../reference/App.tsx | 49 +++---------------- .../requirements.yaml | 13 +++++ .../prompt.md | 2 +- .../reference/App.tsx | 3 -- .../requirements.yaml | 2 +- .../prompt.md | 2 +- .../reference/App.tsx | 37 +++++++++----- .../requirements.yaml | 14 +++--- .../requirements.yaml | 2 +- .../prompt.md | 2 +- .../reference/App.tsx | 4 +- .../requirements.yaml | 2 +- .../requirements.yaml | 10 ++-- .../prompt.md | 2 +- .../requirements.yaml | 10 ++-- .../reference/App.tsx | 7 +-- .../requirements.yaml | 8 +-- .../app/app.config.ts | 11 +++++ .../prompt.md | 2 +- .../reference/app.config.ts | 11 +++++ .../requirements.yaml | 1 + .../prompt.md | 2 +- .../requirements.yaml | 2 +- .../reference/App.tsx | 2 +- .../requirements.yaml | 2 - .../reference/App.tsx | 7 ++- .../requirements.yaml | 8 ++- paper/benchmark-methodology-whitepaper.tex | 4 +- 49 files changed, 159 insertions(+), 182 deletions(-) delete mode 100644 evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts delete mode 100644 evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml rename evals/expo-sdk/{02-rn-expo-camera-active-unmount-focus => 02-rn-expo-camera-preview-pause-focus}/app/App.tsx (100%) rename evals/expo-sdk/{02-rn-expo-camera-active-unmount-focus => 02-rn-expo-camera-preview-pause-focus}/prompt.md (100%) rename evals/expo-sdk/{02-rn-expo-camera-active-unmount-focus => 02-rn-expo-camera-preview-pause-focus}/reference/App.tsx (91%) create mode 100644 evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/requirements.yaml delete mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md delete mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml rename evals/expo-sdk/{03-rn-expo-camera-barcode-audio-config => 03-rn-expo-camera-barcode-scan-config}/app/App.tsx (71%) create mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/prompt.md rename evals/expo-sdk/{03-rn-expo-camera-barcode-audio-config => 03-rn-expo-camera-barcode-scan-config}/reference/App.tsx (63%) create mode 100644 evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/requirements.yaml create mode 100644 evals/expo-sdk/23-rn-expo-updates-request-header-override/app/app.config.ts create mode 100644 evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/app.config.ts diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md index abea4f8b..19ded7b0 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/prompt.md @@ -1 +1 @@ -In the Stack layout, configure the Inbox (index) screen header: set its title and a right-side header button that shows an alert when pressed. There is also a Details screen pushed from the Inbox. Configure the Details screen so that when it is open, its back button reads "Inbox" instead of the default label. +In the Stack layout, configure the Inbox (index) screen header through that screen's options object in the layout: set its title and a right-side header button that shows an alert when pressed. There is also a Details screen pushed from the Inbox. Configure the Details screen so that when it is open, its back button reads a custom label ("All mail") instead of the previous screen's title. diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx index aa8a352c..bfed96b1 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/reference/_layout.tsx @@ -18,7 +18,7 @@ export default function Layout() { diff --git a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml index 50a1cb7a..d1ab5ea4 100644 --- a/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml +++ b/evals/expo-router/03-rn-expo-router-stack-composition-header/requirements.yaml @@ -6,12 +6,12 @@ inputs: - app/details.tsx requirements: - id: uses-stack-screen-options-for-header - description: 'Must configure the header via Stack.Screen options (title/headerRight), not Stack.Toolbar.' + description: "Must configure the header via the screen's options object in the Stack layout (title and a right-side header button)." - id: header-right-shows-alert description: 'The index (Inbox) screen headerRight must render a pressable button whose press handler calls Alert.alert.' - id: sets-inbox-title description: 'Must set the index (Inbox) screen title via its Stack.Screen options.' - id: sets-details-back-title - description: "Must set headerBackTitle in the details screen's Stack.Screen options so the back button on the pushed details screen shows the custom label; setting headerBackTitle on the index screen would not affect the back button." + description: "Must set headerBackTitle in the details screen's Stack.Screen options to a custom label distinct from the previous screen's title (which is the default back label) so the back button on the pushed details screen shows that custom label; setting headerBackTitle on the index screen would not affect the back button." - id: no-react-navigation-header-imports description: 'Must not import React Navigation header components or types directly.' diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx index a14c4536..6354eedd 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/reference/_layout.tsx @@ -2,7 +2,7 @@ import { Stack } from 'expo-router' export default function Layout() { return ( - + ) diff --git a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml index 5979ecc8..70459dca 100644 --- a/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml +++ b/evals/expo-router/04-rn-expo-router-large-title-scroll-child/requirements.yaml @@ -5,10 +5,10 @@ inputs: - app/index.tsx requirements: - id: large-title-option - description: "Must set headerLargeTitle or equivalent large-title Stack option." + description: "Must enable the large title via the Stack's headerLargeTitleEnabled option (the deprecated headerLargeTitle spelling is accepted but not preferred)." - id: scroll-view-first-child - description: "Must make the page content start with a ScrollView or compatible scrollable child." + description: 'Must make the page content start with a ScrollView or compatible scrollable child.' - id: content-inset-adjustment - description: "Must set contentInsetAdjustmentBehavior to automatic on the scrollable so the large title collapses correctly." + description: 'Must set contentInsetAdjustmentBehavior to automatic on the scrollable so the large title collapses correctly.' - id: stack-only - description: "Must use Expo Router Stack, not a manually created native stack." + description: 'Must use Expo Router Stack, not a manually created native stack.' diff --git a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml index e9efe4ea..cab7f28c 100644 --- a/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml +++ b/evals/expo-router/06-rn-expo-router-native-tabs-selected-icons/requirements.yaml @@ -9,5 +9,3 @@ requirements: description: 'The Home trigger must render NativeTabs.Trigger.Icon with sf set to a default symbol "house" and a selected symbol "house.fill".' - id: settings-badge-value description: 'The Settings trigger must render NativeTabs.Trigger.Badge with the value 2.' - - id: uses-trigger-child-apis - description: 'Must configure per-tab presentation through NativeTabs.Trigger.Icon/Badge/Label child components.' diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx index ae7faef3..dae2bbfa 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/reference/_layout.tsx @@ -5,7 +5,6 @@ const signedIn = false export default function Layout() { return ( - diff --git a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml index 48c3ef82..25c01176 100644 --- a/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml +++ b/evals/expo-router/07-rn-expo-router-protected-routes-auth/requirements.yaml @@ -14,5 +14,3 @@ requirements: description: 'The sign-in screen must be wrapped so it is only present when signedIn is false.' - id: guard-boolean-explicit description: 'Must pass explicit guard booleans derived from auth state to Stack.Protected.' - - id: signed-out-fallback - description: 'The layout must keep an unguarded, always-available route (such as index) declared so signed-out users deterministically land somewhere instead of every route being guarded away.' diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md index 8e90d5f1..358d8e8f 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/prompt.md @@ -1 +1 @@ -The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into a server-only module (for example lib/profile.server.ts) and expose it through a route loader that returns the profile name, then render the name in the client from the loader's data so the secret never ships in the client bundle. +The profile route reads process.env.PROFILE_NAME directly in the client component. Move that read into the route's server loader (which is stripped from the client bundle) so it returns the profile name, then render the name in the client from the loader's data so the secret never ships in the client bundle. diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts deleted file mode 100644 index 5a6cd4e6..00000000 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/lib/profile.server.ts +++ /dev/null @@ -1,3 +0,0 @@ -export async function getProfile() { - return { name: process.env.PROFILE_NAME ?? 'Expo' } -} diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx index d1dd6f29..2b3c452d 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/reference/profile.tsx @@ -1,9 +1,8 @@ import { useLoaderData } from 'expo-router' import { Text } from 'react-native' -import { getProfile } from './lib/profile.server' export async function loader() { - return getProfile() + return { name: process.env.PROFILE_NAME ?? 'Expo' } } export default function Profile() { diff --git a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml index 128a003c..0bbdc021 100644 --- a/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml +++ b/evals/expo-router/09-rn-expo-router-static-vs-server-loader/requirements.yaml @@ -6,7 +6,7 @@ inputs: - app/profile.tsx requirements: - id: server-only-code-isolated - description: 'Must place server-only secret/env access in a server-only module or loader boundary.' + description: "Must read the process.env secret only inside the route's loader export, not in the component body or at module scope, so it is stripped from the client bundle." - id: client-route-uses-loader-data description: 'Must render route UI from useLoaderData rather than importing secrets directly.' - id: static-loader-data-serializable diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml b/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml deleted file mode 100644 index 5f529c82..00000000 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: camera-active-derived-from-visibility - description: 'Must pass CameraView an active prop derived from AppState foreground state and the user-enabled preview switch.' - - id: camera-appstate-background-pauses - description: 'Must listen to AppState and set active false when the app leaves the active state.' - - id: camera-view-unmounted-without-permission - description: 'Must not render CameraView at all when camera permission is not granted.' - - id: manual-preview-toggle - description: "Must feed the 'Camera enabled' switch into the CameraView active prop so toggling it pauses/resumes the preview without losing permission state." - - id: cleanup-appstate-subscription - description: 'Must remove the AppState listener on unmount.' diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/app/App.tsx similarity index 100% rename from evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/app/App.tsx rename to evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/app/App.tsx diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/prompt.md similarity index 100% rename from evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/prompt.md rename to evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/prompt.md diff --git a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/reference/App.tsx similarity index 91% rename from evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx rename to evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/reference/App.tsx index 6505e516..9890d450 100644 --- a/evals/expo-sdk/02-rn-expo-camera-active-unmount-focus/reference/App.tsx +++ b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/reference/App.tsx @@ -25,6 +25,17 @@ export default function App() { const cameraActive = Boolean(permission?.granted) && appActive && cameraEnabled + useEffect(() => { + if (!permission?.granted) { + return + } + if (cameraActive) { + cameraRef.current?.resumePreview() + } else { + cameraRef.current?.pausePreview() + } + }, [cameraActive, permission?.granted]) + const handleTakePhoto = async () => { if (!permission?.granted) { await requestPermission() @@ -40,11 +51,7 @@ export default function App() { {permission?.granted ? ( <> - + {!cameraActive && ( Camera paused diff --git a/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/requirements.yaml b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/requirements.yaml new file mode 100644 index 00000000..65e22c16 --- /dev/null +++ b/evals/expo-sdk/02-rn-expo-camera-preview-pause-focus/requirements.yaml @@ -0,0 +1,15 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: preview-pause-from-visibility + description: 'Must pause the preview through the CameraView ref (pausePreview) when the app is not foregrounded and resume it (resumePreview) once foregrounded again, keeping the CameraView mounted.' + - id: camera-appstate-background-pauses + description: 'Must listen to AppState and treat leaving the active state as a signal to pause the live preview.' + - id: camera-view-unmounted-without-permission + description: 'Must not render CameraView at all when camera permission is not granted.' + - id: toggle-drives-preview-pause + description: "Must drive the CameraView ref pausePreview/resumePreview from the 'Camera enabled' switch so toggling it pauses or resumes the preview without unmounting the camera view or losing permission state." + - id: cleanup-appstate-subscription + description: 'Must remove the AppState listener on unmount.' diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md deleted file mode 100644 index c358ef42..00000000 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/prompt.md +++ /dev/null @@ -1 +0,0 @@ -Convert this scanner screen to a real expo-camera preview once camera permission is granted. Restrict scanning to an explicit allowlist so the camera only recognizes QR and EAN-13 codes (not every supported type), and ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Set the camera up for video mode and keep it muted unless audio is enabled. The "Record audio" switch should request microphone permission only when the user turns it on, and stay off if that permission is denied. diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml b/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml deleted file mode 100644 index 1f9ec3c0..00000000 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/requirements.yaml +++ /dev/null @@ -1,15 +0,0 @@ -version: 1 -inputs: - files: - - app/App.tsx -requirements: - - id: uses-camera-view-barcode-settings - description: "Must use CameraView with barcodeScannerSettings and onBarcodeScanned instead of the deprecated BarCodeScanner package/API." - - id: limits-barcode-types - description: "Must configure an explicit barcodeTypes allowlist containing qr and ean13 instead of accepting every type implicitly." - - id: deduplicates-scan-results - description: "Must debounce or deduplicate repeated barcode scan events before updating state." - - id: microphone-request-on-video-intent - description: "Must request microphone permission only from the user action that enables video/audio capture." - - id: audio-gated-video-mode - description: "Must not enable audio recording controls unless microphone permission is granted or the camera is explicitly muted." diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/app/App.tsx similarity index 71% rename from evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx rename to evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/app/App.tsx index d2df74e2..22118f32 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/app/App.tsx +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/app/App.tsx @@ -1,11 +1,10 @@ import { useState } from 'react' -import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { - const [recordAudio, setRecordAudio] = useState(false) const [lastScan, setLastScan] = useState(null) - const handleStartRecording = () => {} + const handleEnableCamera = () => {} return ( @@ -21,13 +20,8 @@ export default function App() { {lastScan ?? '—'} - - Record audio - - - - - Record Video + + Enable Camera ) @@ -68,15 +62,6 @@ const styles = StyleSheet.create({ color: '#111827', fontWeight: '600', }, - row: { - alignItems: 'center', - flexDirection: 'row', - justifyContent: 'space-between', - }, - rowLabel: { - color: '#111827', - fontSize: 16, - }, scanFrame: { borderColor: '#22c55e', borderRadius: 8, diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/prompt.md b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/prompt.md new file mode 100644 index 00000000..52764be5 --- /dev/null +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/prompt.md @@ -0,0 +1 @@ +Convert this scanner screen to a real expo-camera preview once camera permission is granted. When permission has not been granted, keep the placeholder frame and offer a button that requests it. Restrict scanning to an explicit allowlist so the camera only recognizes QR and EAN-13 codes (not every supported type), and ignore repeats of the value that was just scanned so the "Last scan" field does not thrash on the same code. Render the most recent scanned value in the "Last scan" field. diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/reference/App.tsx similarity index 63% rename from evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx rename to evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/reference/App.tsx index 543e4fcc..748c5309 100644 --- a/evals/expo-sdk/03-rn-expo-camera-barcode-audio-config/reference/App.tsx +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/reference/App.tsx @@ -1,32 +1,13 @@ -import { CameraView, useCameraPermissions, useMicrophonePermissions } from 'expo-camera' +import { CameraView, useCameraPermissions } from 'expo-camera' import { useRef, useState } from 'react' -import { Pressable, StyleSheet, Switch, Text, View } from 'react-native' +import { Pressable, StyleSheet, Text, View } from 'react-native' export default function App() { const [cameraPermission, requestCamera] = useCameraPermissions() - const [micPermission, requestMic] = useMicrophonePermissions() - const [recordAudio, setRecordAudio] = useState(false) const [lastScan, setLastScan] = useState(null) const lastScanRef = useRef(null) const cameraRef = useRef(null) - const handleToggleAudio = async (value: boolean) => { - if (!value) { - setRecordAudio(false) - return - } - const result = micPermission?.granted ? micPermission : await requestMic() - setRecordAudio(result.granted) - } - - const handleStartRecording = async () => { - if (!cameraPermission?.granted) { - await requestCamera() - return - } - await cameraRef.current?.recordAsync() - } - return ( Scanner @@ -35,8 +16,6 @@ export default function App() { {cameraPermission?.granted ? ( { if (event.data === lastScanRef.current) return @@ -58,16 +37,11 @@ export default function App() { {lastScan ?? '—'} - - Record audio - - - - - - {cameraPermission?.granted ? 'Record Video' : 'Enable Camera'} - - + {!cameraPermission?.granted && ( + requestCamera()}> + Enable Camera + + )} ) } @@ -112,15 +86,6 @@ const styles = StyleSheet.create({ color: '#111827', fontWeight: '600', }, - row: { - alignItems: 'center', - flexDirection: 'row', - justifyContent: 'space-between', - }, - rowLabel: { - color: '#111827', - fontSize: 16, - }, scanFrame: { borderColor: '#22c55e', borderRadius: 8, diff --git a/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/requirements.yaml b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/requirements.yaml new file mode 100644 index 00000000..14c16565 --- /dev/null +++ b/evals/expo-sdk/03-rn-expo-camera-barcode-scan-config/requirements.yaml @@ -0,0 +1,13 @@ +version: 1 +inputs: + files: + - app/App.tsx +requirements: + - id: permission-gated-preview + description: 'Must render the CameraView preview only once camera permission is granted and otherwise show the placeholder with a button that requests permission.' + - id: limits-barcode-types + description: 'Must configure an explicit barcodeTypes allowlist containing qr and ean13 instead of accepting every type implicitly.' + - id: deduplicates-scan-results + description: 'Must ignore repeats of the value that was just scanned before updating the last-scan state.' + - id: renders-last-scan + description: 'Must render the most recent scanned value in the "Last scan" field.' diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md index 08bf3c05..7bc10555 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/prompt.md @@ -1 +1 @@ -Wire up the Choose from Library button to expo-image-picker. Launch the picker only from the button press, show the selected image in the preview, and keep a stable empty state when the user cancels — cancellation must never crash. +Wire up the Choose from Library button to expo-image-picker. Launch the picker only from the button press, offer images only, show the selected image in the preview, and keep a stable empty state when the user cancels — cancellation must never crash. diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx index 51613bf4..43b03005 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/reference/App.tsx @@ -8,9 +8,7 @@ export default function App() { const handlePickImage = async () => { const result = await ImagePicker.launchImageLibraryAsync({ - allowsEditing: true, mediaTypes: ['images'], - quality: 0.8, }) if (result.canceled || !result.assets?.length) { setImageUri(null) @@ -18,7 +16,6 @@ export default function App() { return } setImageUri(result.assets[0].uri) - setStatus('Image selected') } return ( diff --git a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml index a8a13365..2f67fafc 100644 --- a/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml +++ b/evals/expo-sdk/04-rn-expo-image-picker-canceled-assets-guard/requirements.yaml @@ -12,4 +12,4 @@ requirements: - id: uses-current-media-types-array description: 'Must use the current MediaType array form such as mediaTypes: ["images"] rather than depending on deprecated MediaTypeOptions.' - id: renders-empty-state - description: 'Must keep the preview in its empty state from the picker-cancellation branch (the result.canceled path) without crashing, rather than relying only on the static initial fallback.' + description: 'Must keep the UI in its stable empty state without crashing when the user cancels the picker.' diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md index e2d7748a..2236f778 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/prompt.md @@ -1 +1 @@ -Wire up the Choose Video button to a video-library picker. Check media-library permission before launching (from the button, not on mount), render a distinct state for denied or limited access, select videos only, and display the chosen video after validating it is a video. +Wire up a video-library picker. Picking a video must always work — do not block the picker on media-library permission. Separately, offer a control that requests media-library permission and surfaces the current access level (full, limited, or none) as a persistent notice. Select videos only, and display the chosen video after validating it is a video. diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx index 2180b0a2..0324e805 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/reference/App.tsx @@ -7,24 +7,23 @@ export default function App() { const [status, setStatus] = useState('No video selected') const [accessNotice, setAccessNotice] = useState(null) - const handlePickVideo = async () => { + const handleCheckAccess = async () => { const existing = await ImagePicker.getMediaLibraryPermissionsAsync() const permission = existing.granted ? existing : await ImagePicker.requestMediaLibraryPermissionsAsync(false) - if (!permission.granted) { + if (permission.accessPrivileges === 'all') { + setAccessNotice('Full library access') + } else if (permission.accessPrivileges === 'limited') { setAccessNotice( - permission.canAskAgain - ? 'Video access denied' - : 'Enable video access in Settings' + 'Limited library access — only selected videos are available' ) - return + } else { + setAccessNotice('No library access — you can still pick a single video') } - setAccessNotice( - permission.accessPrivileges === 'limited' - ? 'Limited library access — only selected videos are available' - : null - ) + } + + const handlePickVideo = async () => { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['videos'], }) @@ -59,6 +58,10 @@ export default function App() { {videoUri ? {status} : null} + + Check Library Access + + Choose Video @@ -73,6 +76,18 @@ const styles = StyleSheet.create({ paddingHorizontal: 14, paddingVertical: 10, }, + buttonSecondary: { + borderColor: '#111827', + borderRadius: 10, + borderWidth: 1, + paddingHorizontal: 14, + paddingVertical: 10, + }, + buttonSecondaryText: { + color: '#111827', + fontWeight: '600', + textAlign: 'center', + }, buttonText: { color: '#fff', fontWeight: '600', diff --git a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml index db8d73fd..049e39fb 100644 --- a/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml +++ b/evals/expo-sdk/05-rn-expo-image-picker-video-permission-nuance/requirements.yaml @@ -3,13 +3,11 @@ inputs: files: - app/App.tsx requirements: - - id: permission-checked-before-picker - description: "Must call getMediaLibraryPermissionsAsync/requestMediaLibraryPermissionsAsync before launching the picker." - - id: request-not-on-mount - description: "Must request media-library permission from a user action, not on initial mount." + - id: picker-not-gated-on-permission + description: 'Must launch launchImageLibraryAsync without gating it on a media-library permission check, since the library picker requires no permission.' + - id: access-level-notice-from-permission + description: 'Must surface the current access level (full, limited, or none) as a persistent notice derived from the media-library permission response accessPrivileges.' - id: current-video-media-type - description: "Must use mediaTypes: [\"videos\"] or \"videos\" instead of deprecated MediaTypeOptions.Videos." - - id: handles-limited-or-denied - description: "Must render a deterministic UI for denied or limited media access and avoid assuming full-library access." + description: 'Must use mediaTypes: ["videos"] or "videos" instead of deprecated MediaTypeOptions.Videos.' - id: video-asset-guard - description: "Must verify the selected asset exists and is a video before reading uri/duration fields." + description: 'Must verify the selected asset exists and is a video before reading uri/duration fields.' diff --git a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml index 9eb65a96..6cc02a59 100644 --- a/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml +++ b/evals/expo-sdk/12-rn-expo-filesystem-object-api-read-write/requirements.yaml @@ -10,4 +10,4 @@ requirements: - id: uses-file-instance-read-write description: 'Must call File instance methods such as write() and text() for read/write operations.' - id: handles-read-missing-file - description: 'Must handle missing-file or first-run reads with fallback text instead of crashing.' + description: 'Must actually read the file through the File API and drive the fallback text from a caught missing-file/failed read (e.g. try/catch around text()), not from a static status or by never reading.' diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md index 1c5a6cf1..13b28965 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/prompt.md @@ -1 +1 @@ -Wire up the Save button to save the generated image to the photo library. Request write-only permission (the app never browses existing photos), do not read the library, and render a deterministic state when permission is denied. +Wire up the Save button to save the generated image to the photo library. Request write-only permission scoped to photos (the app only ever saves photos and never browses existing ones), do not read the library, and render a deterministic state when permission is denied. diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx index a56cc7f5..461c7bd5 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/reference/App.tsx @@ -22,7 +22,9 @@ export default function App() { try { const cache = new Directory(Paths.cache, 'posters') cache.create({ idempotent: true, intermediates: true }) - const file = await File.downloadFileAsync(GENERATED_IMAGE_URI, cache) + const file = await File.downloadFileAsync(GENERATED_IMAGE_URI, cache, { + idempotent: true, + }) await MediaLibrary.Asset.create(file.uri) setSaveState('saved') } catch { diff --git a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml index 75f7a431..4fb6c2b4 100644 --- a/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml +++ b/evals/expo-sdk/15-rn-expo-media-library-granular-writeonly/requirements.yaml @@ -10,4 +10,4 @@ requirements: - id: saves-image-via-write-path description: 'Must save the generated image to the library through a write/save path (such as Asset.create) once write-only permission is granted.' - id: denied-fallback - description: 'Must render a deterministic denied-permission fallback.' + description: 'Must drive the denied state from the permission response (e.g. the granted flag being false), not from a static or dead branch.' diff --git a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml index c1625080..3b6446e0 100644 --- a/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml +++ b/evals/expo-sdk/17-rn-expo-calendar-dev-build-permissions/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: uses-request-calendar-permissions - description: "Must use Calendar.requestCalendarPermissions instead of requestCalendarPermissionsAsync from the root module." + description: 'Must use Calendar.requestCalendarPermissions instead of requestCalendarPermissionsAsync from the root module.' - id: uses-get-calendars-current - description: "Must use Calendar.getCalendars instead of getCalendarsAsync from the root module." + description: 'Must use Calendar.getCalendars instead of getCalendarsAsync from the root module.' - id: uses-calendar-instance-create-event - description: "Must create events through a calendar object createEvent method rather than root createEventAsync." + description: 'Must create events through a calendar object createEvent method rather than root createEventAsync.' - id: permission-denied-fallback - description: "Must render a deterministic fallback when calendar permission is denied." + description: 'Must drive the denied fallback from the actual permission check result (e.g. the granted flag being false), not from an unconditional status message.' - id: selects-writable-calendar - description: "Must choose a writable calendar or handle the absence of one explicitly." + description: 'Must choose a writable calendar or handle the absence of one explicitly.' diff --git a/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md index 8a47e2bc..20c8d690 100644 --- a/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md +++ b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/prompt.md @@ -1 +1 @@ -A video thumbnail feature is broken after an SDK upgrade. Fix it to generate thumbnail images from a video file at specific time offsets using current Expo APIs. Handle cases where no thumbnails are generated. \ No newline at end of file +We are consolidating dependencies and removing the standalone expo-video-thumbnails package. This screen currently uses it to generate a preview image from a video file. Rework it to generate the thumbnails through the SDK 56 video player's thumbnail API instead. Request thumbnails at multiple explicit time offsets and handle the case where no thumbnails come back. diff --git a/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml index c2d6f0cd..fcc4cfc2 100644 --- a/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml +++ b/evals/expo-sdk/21-rn-expo-video-thumbnails-replacement/requirements.yaml @@ -4,12 +4,12 @@ inputs: - app/App.tsx requirements: - id: no-expo-video-thumbnails - description: "Must not import or call expo-video-thumbnails." + description: 'Must not import or call expo-video-thumbnails.' - id: uses-video-player-thumbnail-api - description: "Must use the expo-video player thumbnail API such as generateThumbnailsAsync." + description: 'Must use the SDK 56 video player thumbnail API such as generateThumbnailsAsync.' - id: handles-empty-thumbnail-array - description: "Must handle an empty thumbnails array with fallback UI." + description: 'Must handle an empty thumbnails array with fallback UI.' - id: thumbnail-time-explicit - description: "Must request thumbnails at explicit second offsets." + description: 'Must request thumbnails at multiple explicit seconds-based time offsets via the video player thumbnail API, not a single offset.' - id: thumbnail-image-rendered - description: "Must render the generated thumbnail image/URI or a deterministic fallback." + description: 'Must keep rendering the generated thumbnail(s) or the deterministic fallback UI.' diff --git a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx index 0613860c..2cefd3a4 100644 --- a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx +++ b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/reference/App.tsx @@ -10,18 +10,13 @@ import { export default function App() { const { - currentlyRunning, isDownloading, downloadProgress, isUpdateAvailable, isUpdatePending, downloadError, } = Updates.useUpdates() - const [status, setStatus] = useState( - currentlyRunning.isEmbeddedLaunch - ? 'Running embedded build.' - : 'Up to date.' - ) + const [status, setStatus] = useState('Up to date.') const checkForUpdate = async () => { setStatus('Checking…') diff --git a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml index 8b99e821..016a2f59 100644 --- a/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml +++ b/evals/expo-sdk/22-rn-expo-updates-download-progress-reload-screen/requirements.yaml @@ -4,10 +4,10 @@ inputs: - app/App.tsx requirements: - id: uses-useupdates-state - description: 'Must use Updates.useUpdates() to read isDownloading, downloadProgress, isUpdateAvailable, isUpdatePending, and currentlyRunning state.' + description: 'Must read the update and download state (isUpdateAvailable, isDownloading, downloadProgress, downloadError) from Updates.useUpdates().' - id: download-progress-rendered - description: 'Must render downloadProgress or a deterministic progress state while downloading.' + description: 'Must render the download progress from the updates hook state, not a hardcoded local value.' - id: no-post-reload-assumption - description: 'Must not update React state after awaiting reloadAsync as if execution will reliably continue.' + description: 'Must make reloadAsync the final step of the apply path, with no state updates sequenced after it.' - id: handles-disabled-or-error - description: 'Must render a fallback for unavailable updates or download errors.' + description: 'Must drive the no-update and download-error fallbacks from the check/download results, not a static default message.' diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/app/app.config.ts b/evals/expo-sdk/23-rn-expo-updates-request-header-override/app/app.config.ts new file mode 100644 index 00000000..8b9a65b4 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/app/app.config.ts @@ -0,0 +1,11 @@ +export default { + expo: { + name: 'release-channel-switcher', + slug: 'release-channel-switcher', + updates: { + requestHeaders: { + 'expo-channel-name': 'production', + }, + }, + }, +} diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md b/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md index c8a42aef..7e66341b 100644 --- a/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/prompt.md @@ -1 +1 @@ -Wire up the release-channel switcher (production, staging, beta): override the expo-updates request headers for the selected channel and check for an update from it, and reset the override back to default. Show which channel is currently active. +Wire up the release-channel switcher (production, staging, beta): override the expo-updates request headers for the selected channel and check for an update from it, and reset the override back to default. Show which channel is currently active. The channel header is already declared in the app config, so keep the override within the declared set. diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/app.config.ts b/evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/app.config.ts new file mode 100644 index 00000000..8b9a65b4 --- /dev/null +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/reference/app.config.ts @@ -0,0 +1,11 @@ +export default { + expo: { + name: 'release-channel-switcher', + slug: 'release-channel-switcher', + updates: { + requestHeaders: { + 'expo-channel-name': 'production', + }, + }, + }, +} diff --git a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml index 805da14f..689f767c 100644 --- a/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml +++ b/evals/expo-sdk/23-rn-expo-updates-request-header-override/requirements.yaml @@ -2,6 +2,7 @@ version: 1 inputs: files: - app/App.tsx + - app/app.config.ts requirements: - id: uses-header-override-api description: 'Must call Updates.setUpdateRequestHeadersOverride with a record or null.' diff --git a/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md index ad100e3c..25b24095 100644 --- a/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md +++ b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/prompt.md @@ -1 +1 @@ -Configure build properties for an SDK 56 Expo project. The iOS build should use prebuilt dependencies where possible, and Android SDK versions should match current requirements. Use the expo-build-properties config plugin. \ No newline at end of file +Configure build properties for an SDK 56 Expo project. The iOS build should use prebuilt dependencies where possible, and Android SDK versions should match current requirements. Make the prebuilt-dependencies choice explicit in the config so it stays fixed even if the plugin's defaults change later. Use the expo-build-properties config plugin. diff --git a/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml index 1572db5d..583b7b0c 100644 --- a/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml +++ b/evals/expo-sdk/25-rn-expo-build-properties-precompiled-headers/requirements.yaml @@ -5,7 +5,7 @@ inputs: - app/app.config.ts requirements: - id: ios-precompiled-rn-enabled - description: 'Must opt into the SDK 56-era precompiled React Native dependency path with buildReactNativeFromSource: false or the current equivalent.' + description: 'Must explicitly pin the precompiled React Native choice in the plugin ios options (buildReactNativeFromSource: false or the current equivalent) rather than relying on the default.' - id: keeps-static-frameworks-intent description: 'Must preserve the existing useFrameworks: "static" iOS setting while adding the new build properties.' - id: android-sdk-values-current diff --git a/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx index bdb53b8c..24636d1d 100644 --- a/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx +++ b/evals/expo-ui/01-rn-expo-ui-universal-layout-controls/reference/App.tsx @@ -25,7 +25,7 @@ export default function App() { - +