mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Compare commits
8
Commits
ecff9e2ec8
...
6883befff3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6883befff3 | ||
|
|
636811e66a | ||
|
|
d825e3d80c | ||
|
|
13094267a6 | ||
|
|
ecc31a13a2 | ||
|
|
7a76936829 | ||
|
|
9609a9084b | ||
|
|
90cde4aca4 |
No files matched your search
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 2026-08-31-expo-prebuild-native-regression
|
||||
date: 2026-08-31
|
||||
status: promoted
|
||||
scope: apps/mobile native projects (ios/, android/) and expo prebuild
|
||||
evidence: v1.0.8 SDK 54 to 56 upgrade, commits 604eec3, 7aca39a, 6bd04a6, 79233f5, b8cb2add
|
||||
destination: apps/mobile/scripts/release-preflight.mjs, apps/mobile/scripts/release-preflight.test.mjs, and docs/releasing.md
|
||||
review_after: 2026-11-30
|
||||
---
|
||||
|
||||
## Symptom
|
||||
|
||||
`expo prebuild --clean` during the SDK 54 to 56 upgrade (and the
|
||||
@bacons/apple-targets 0.1 to 5.0 bump) silently regressed four checked-in
|
||||
native invariants. Each regression was caught only by a release gate or by
|
||||
manual diffing against the last shipped tag (3fc6f8a, v1.0.7), not by
|
||||
prebuild itself.
|
||||
|
||||
## Reproduction
|
||||
|
||||
Run `expo prebuild --clean` in apps/mobile against the upgraded SDK and diff
|
||||
the regenerated ios/ and android/ projects against the previously committed
|
||||
projects.
|
||||
|
||||
## Cause
|
||||
|
||||
1. Widget identity: apple-targets 5.x derives PRODUCT_BUNDLE_IDENTIFIER from
|
||||
the target folder name, changing com.sauci.app.LiveDrawWidget to
|
||||
com.sauci.app.widget, and repointed CODE_SIGN_ENTITLEMENTS to the
|
||||
gitignored ios/.targets/LiveDrawWidget/generated.entitlements.
|
||||
2. Android manifest lost the tools:node="remove" attributes on
|
||||
READ_MEDIA_IMAGES and READ_MEDIA_VIDEO, so the built AAB regained
|
||||
Play-forbidden permissions (verified via bundletool dump on the rejected
|
||||
build 50 AAB).
|
||||
3. iOS Info.plist gained dev-launcher-only keys NSBonjourServices
|
||||
(_expo._tcp), NSLocalNetworkUsageDescription, and RCTMetroPort.
|
||||
4. android/gradle.properties reset to stock -Xmx2048m
|
||||
-XX:MaxMetaspaceSize=512m, causing Metaspace OOM in kspReleaseKotlin/CMake
|
||||
under RN 0.85.
|
||||
|
||||
Separately, a package absent from the new SDK's bundledNativeModules
|
||||
(expo-av) has no compatible release and fails the iOS archive (EXAV.h
|
||||
imports removed ExpoModulesCore headers).
|
||||
|
||||
## Remediation
|
||||
|
||||
Fixed by restoring widget identity and tracking
|
||||
targets/widget/generated.entitlements with a pinned bundleIdentifier
|
||||
(604eec3); restoring manifest tools:node="remove" attributes (7aca39a);
|
||||
removing the dev-launcher-only Info.plist keys (6bd04a6); raising
|
||||
gradle.properties memory to 4096m/1024m (79233f5); and migrating expo-av to
|
||||
expo-video/expo-audio (b8cb2add).
|
||||
|
||||
Extend apps/mobile/scripts/release-preflight.mjs with executable checks for
|
||||
items 2 and 3 (item 1 is already covered by the existing LiveDrawWidget
|
||||
preflight check; item 4 hard-fails the build by itself). Add an "After
|
||||
native regeneration" checklist to docs/releasing.md.
|
||||
|
||||
## Evidence
|
||||
|
||||
`node apps/mobile/scripts/release-preflight.mjs` fails if the tracked
|
||||
AndroidManifest.xml lacks tools:node="remove" on READ_MEDIA_IMAGES or
|
||||
READ_MEDIA_VIDEO, or if ios/Sauci/Info.plist contains NSBonjourServices,
|
||||
NSLocalNetworkUsageDescription, or RCTMetroPort.
|
||||
`node --test apps/mobile/scripts/release-preflight.test.mjs` covers the new
|
||||
checks.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 2026-08-31-local-eas-build-preconditions
|
||||
date: 2026-08-31
|
||||
status: promoted
|
||||
scope: apps/mobile local EAS release builds
|
||||
evidence: v1.0.8 local EAS build session, commit d8bedea
|
||||
destination: docs/releasing.md
|
||||
review_after: 2026-11-30
|
||||
---
|
||||
|
||||
## Symptom
|
||||
|
||||
Local EAS release builds failed before native compilation for environment
|
||||
reasons unrelated to the app source, and a successful iOS build left the
|
||||
tracked source in a state that fails release-preflight afterward.
|
||||
|
||||
## Reproduction
|
||||
|
||||
Run `eas build --local` from a non-interactive shell without first exporting
|
||||
ANDROID_HOME/ANDROID_SDK_ROOT/JAVA_HOME: fails with "SDK location not
|
||||
found" because non-interactive shells do not load the user profile. Run it
|
||||
with a non-empty EAS_LOCAL_BUILD_WORKINGDIR: fails with "Workingdir is not
|
||||
empty". Run it outside apps/mobile: eas cannot find the project. Pipe the
|
||||
build log through `tail`: the full log needed for diagnosis is lost. After a
|
||||
successful iOS build, EAS auto-increment updates both Info.plists but not
|
||||
the widget target's CURRENT_PROJECT_VERSION in the pbxproj, so
|
||||
release-preflight fails until it is synced.
|
||||
|
||||
## Cause
|
||||
|
||||
`eas` must be installed as a global CLI (scripts call bare `eas`; eas-cli
|
||||
23.0.0 verified). Non-interactive shells used for automation do not source
|
||||
the profile that normally exports the Android/Java environment variables.
|
||||
EAS_LOCAL_BUILD_WORKINGDIR must not exist or be empty. EAS iOS
|
||||
auto-increment writes plist versions but does not touch the widget target's
|
||||
pbxproj CURRENT_PROJECT_VERSION, so it drifts from the app's build number by
|
||||
one increment after every successful build.
|
||||
|
||||
## Remediation
|
||||
|
||||
Before a local EAS build: verify `eas` is on PATH, explicitly export
|
||||
ANDROID_HOME, ANDROID_SDK_ROOT, and JAVA_HOME (JDK 17), ensure
|
||||
EAS_LOCAL_BUILD_WORKINGDIR does not exist or is empty, and run from
|
||||
apps/mobile. Capture the full build log to a file rather than piping through
|
||||
`tail`. After a successful build, sync the widget's CURRENT_PROJECT_VERSION
|
||||
to the new build number (commit d8bedea, sed 46 to 47) and sync
|
||||
ios/Podfile.lock from the successful build's working directory when
|
||||
dependencies changed, since the archive's pod install resolution is
|
||||
authoritative and local CocoaPods here is broken.
|
||||
|
||||
## Evidence
|
||||
|
||||
docs/releasing.md's local-build section documents the environment
|
||||
preconditions and the post-build widget CURRENT_PROJECT_VERSION and
|
||||
Podfile.lock sync steps; `npm run release:preflight` passes after the sync.
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 2026-08-31-npm-lockfile-divergence
|
||||
date: 2026-08-31
|
||||
status: promoted
|
||||
scope: root package.json, package-lock.json, apps/web dependencies, CI
|
||||
evidence: v1.0.8 lockfile investigation, commits 90cde4a, 9609a90
|
||||
destination: docs/development/dependencies.md
|
||||
review_after: 2026-11-30
|
||||
---
|
||||
|
||||
## Symptom
|
||||
|
||||
CI and the API Docker image (node 20.19.4/npm 10.8.2, per .nvmrc) broke
|
||||
invisibly while a lockfile regenerated on this dev machine (node 26/npm
|
||||
11.19) passed local `npm ci`. Pushes to staging bypass required status
|
||||
checks, so the red CI ran unnoticed for hours.
|
||||
|
||||
## Reproduction
|
||||
|
||||
Regenerate package-lock.json with npm 11 on a wildcard-range dependency
|
||||
(react-native-worklets depends on `@react-native/metro-config: "*"`), then
|
||||
run `npm ci` under node 20.19.4/npm 10.8.2. npm 10 requires 0.85.3 at that
|
||||
tree position; npm 11 resolves/hoists 0.87.x there. `npm ci` fails with
|
||||
"Invalid: lock file's ... does not satisfy". The reverse direction also
|
||||
fails: a lock regenerated by npm 10 fails `npm ci` under npm 11 with missing
|
||||
platform-optional binaries (@next/swc-linux-x64-gnu breaking `next build`,
|
||||
@rollup/rollup-linux-x64-gnu breaking the API Docker tsup build, lightningcss
|
||||
variants breaking local npm ci), matching the npm/cli#4828-style
|
||||
optional-dependency resolution gap.
|
||||
|
||||
## Cause
|
||||
|
||||
Two different npm major versions in active use (CI/Docker on npm 10, this
|
||||
dev machine on npm 11) resolve wildcard/range dependencies to different
|
||||
versions at the same tree position, and each npm's own platform-optional
|
||||
binary selection is not portable to the other npm's lockfile.
|
||||
|
||||
## Remediation
|
||||
|
||||
Pin the wildcard-range dependency via a root package.json override
|
||||
(`"@react-native/metro-config": "0.85.3"`, alongside the existing
|
||||
rollup/react-native/expo pins). Pin apps/web `@next/swc` linux/darwin
|
||||
binaries as direct optionalDependencies (must be bumped together with any
|
||||
`next` version bump). Regenerate the lock and validate it both ways: local
|
||||
`npm ci` plus `npm run verify:fast`, and
|
||||
`docker run --platform linux/amd64 node:20.19.4 ... npm ci` (the
|
||||
`--platform` flag is mandatory; Apple Silicon Docker otherwise runs arm64
|
||||
and the platform-binary check is meaningless). After any push that bypassed
|
||||
required status checks, check `gh run list --branch staging`.
|
||||
|
||||
## Evidence
|
||||
|
||||
commits 90cde4a and 9609a90 add the override and optionalDependencies pins
|
||||
and record a lockfile that passes both the amd64-emulated `npm ci` under
|
||||
node 20.19.4 and local `npm ci` plus `npm run verify:fast`.
|
||||
@@ -39,3 +39,11 @@ terraform
|
||||
.claude
|
||||
.codex
|
||||
.ralph
|
||||
|
||||
# The admin app builds from this same monorepo context (apps/admin/Dockerfile).
|
||||
!apps/admin
|
||||
!apps/admin/**
|
||||
|
||||
# Host build artefacts must never leak into any image context.
|
||||
**/node_modules
|
||||
**/dist
|
||||
@@ -24,9 +24,14 @@ jobs:
|
||||
echo "master is frozen; target staging or main" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$BASE_BRANCH" = "main" ] && [ "$HEAD_BRANCH" != "staging" ]; then
|
||||
echo "Only staging may be promoted to main" >&2
|
||||
exit 1
|
||||
if [ "$BASE_BRANCH" = "main" ]; then
|
||||
case "$HEAD_BRANCH" in
|
||||
staging|hotfix/*|release/*) ;;
|
||||
*)
|
||||
echo "main takes staging promotions, or a hotfix/* or release/* branch for direct work" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
if [ "$BASE_BRANCH" != "staging" ] && [ "$BASE_BRANCH" != "main" ]; then
|
||||
echo "Feature pull requests target staging; promotions target main" >&2
|
||||
|
||||
@@ -76,6 +76,7 @@ environment limitation; do not call it a passing product check.
|
||||
|---|---|
|
||||
| System boundaries and data flow | `docs/architecture/system.md` |
|
||||
| Local services, ports, fixtures | `docs/development/local-stack.md` |
|
||||
| Dependency and lockfile discipline | `docs/development/dependencies.md` |
|
||||
| Test layers and required gates | `docs/testing/strategy.md` |
|
||||
| Database migration safety | `docs/operations/database-migrations.md` |
|
||||
| Agent roles and effort routing | `docs/agents/routing.md` |
|
||||
|
||||
@@ -13,3 +13,5 @@ native iOS/Android targets.
|
||||
- Add stable accessibility labels or `testID` values for critical interactions.
|
||||
- Verify focused Jest tests, typecheck, lint, then native/Expo behavior as risk
|
||||
requires. UI work needs observable simulator evidence.
|
||||
- Before and after any `expo prebuild`, follow the "After native regeneration"
|
||||
checklist in `docs/releasing.md`.
|
||||
@@ -69,10 +69,12 @@ export default function MatchesScreen() {
|
||||
checkNudgeCooldown,
|
||||
} = useMatchStore();
|
||||
const { user, couple, partner } = useAuthStore();
|
||||
const userId = user?.id;
|
||||
const router = useRouter();
|
||||
const { width } = useWindowDimensions();
|
||||
const isWideScreen = width > MAX_CONTENT_WIDTH;
|
||||
const [showTutorial, setShowTutorial] = useState(false);
|
||||
const tutorialDismissedRef = useRef(false);
|
||||
const [nudgeFeedback, setNudgeFeedback] = useState<string | null>(null);
|
||||
const [headerHeight, setHeaderHeight] = useState(130);
|
||||
|
||||
@@ -104,21 +106,30 @@ export default function MatchesScreen() {
|
||||
// Check if tutorial should be shown when screen is focused or matches change
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
let isActive = true;
|
||||
|
||||
const checkTutorial = async () => {
|
||||
if (matches.length > 0) {
|
||||
const seen = await hasSeenMatchesTutorial();
|
||||
if (!seen) {
|
||||
if (matches.length > 0 && userId) {
|
||||
const seen = await hasSeenMatchesTutorial(userId);
|
||||
if (isActive && !tutorialDismissedRef.current && !seen) {
|
||||
setShowTutorial(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkTutorial();
|
||||
}, [matches.length])
|
||||
void checkTutorial();
|
||||
|
||||
return () => {
|
||||
isActive = false;
|
||||
};
|
||||
}, [matches.length, userId])
|
||||
);
|
||||
|
||||
const handleTutorialComplete = async () => {
|
||||
await markMatchesTutorialSeen();
|
||||
if (!userId) return;
|
||||
|
||||
tutorialDismissedRef.current = true;
|
||||
setShowTutorial(false);
|
||||
await markMatchesTutorialSeen(userId);
|
||||
};
|
||||
|
||||
// Load whichever view is showing, once. Returning to this tab reuses what is
|
||||
|
||||
@@ -39,6 +39,7 @@ export function validateReleaseSources({ root = repoRoot, isTracked } = {}) {
|
||||
const androidGradle = file('apps/mobile/android/app/build.gradle');
|
||||
const androidStrings = file('apps/mobile/android/app/src/main/res/values/strings.xml');
|
||||
const xcode = file('apps/mobile/ios/Sauci.xcodeproj/project.pbxproj');
|
||||
const androidManifest = file('apps/mobile/android/app/src/main/AndroidManifest.xml');
|
||||
const iosInfo = file('apps/mobile/ios/Sauci/Info.plist');
|
||||
const widgetInfo = file('apps/mobile/targets/widget/Info.plist');
|
||||
const iosExpo = file('apps/mobile/ios/Sauci/Supporting/Expo.plist');
|
||||
@@ -70,6 +71,17 @@ export function validateReleaseSources({ root = repoRoot, isTracked } = {}) {
|
||||
fail(`iOS app, widget, and effective widget Xcode build numbers disagree: app ${appBuild}; widget plist ${widgetBuild}; widget settings ${widgetBuildSettings.join(', ')}`);
|
||||
}
|
||||
|
||||
for (const permission of ['READ_MEDIA_IMAGES', 'READ_MEDIA_VIDEO']) {
|
||||
const removed = new RegExp(`<uses-permission[^>]*android:name="android\\.permission\\.${permission}"[^>]*tools:node="remove"`).test(androidManifest);
|
||||
if (!removed) fail(`AndroidManifest.xml must keep tools:node="remove" on ${permission} (expo prebuild regresses this)`);
|
||||
}
|
||||
|
||||
const forbiddenPlistKeys = ['NSBonjourServices', 'NSLocalNetworkUsageDescription', 'RCTMetroPort'];
|
||||
const foundDevLauncherKeys = forbiddenPlistKeys.filter((key) => iosInfo.includes(key));
|
||||
if (foundDevLauncherKeys.length) {
|
||||
fail(`ios/Sauci/Info.plist must not contain dev-launcher-only keys reintroduced by expo prebuild: ${foundDevLauncherKeys.join(', ')}`);
|
||||
}
|
||||
|
||||
const tracked = isTracked ?? ((relative) => gitStatus(['ls-files', '--error-unmatch', relative], root) === 0);
|
||||
if (!tracked(certificatePath)) fail(`${certificatePath} must be tracked`);
|
||||
const archiveIgnore = existsSync(join(root, '.easignore')) ? '.easignore' : '.gitignore';
|
||||
|
||||
@@ -67,6 +67,38 @@ test('rejects an OTA certificate without its root archive allowlist', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects an Android manifest that lost the media permission removal (expo prebuild regression)', () => {
|
||||
const root = fixture();
|
||||
try {
|
||||
const manifest = 'apps/mobile/android/app/src/main/AndroidManifest.xml';
|
||||
replace(
|
||||
root,
|
||||
manifest,
|
||||
'<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove"/>',
|
||||
'<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>',
|
||||
);
|
||||
assert.throws(() => validate(root), /READ_MEDIA_IMAGES \(expo prebuild regresses this\)/);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('rejects an iOS Info.plist that regained dev-launcher-only keys (expo prebuild regression)', () => {
|
||||
const root = fixture();
|
||||
try {
|
||||
const infoPlist = 'apps/mobile/ios/Sauci/Info.plist';
|
||||
replace(
|
||||
root,
|
||||
infoPlist,
|
||||
'</dict>\n</plist>',
|
||||
'<key>NSBonjourServices</key>\n<array><string>_expo._tcp</string></array>\n</dict>\n</plist>',
|
||||
);
|
||||
assert.throws(() => validate(root), /dev-launcher-only keys reintroduced by expo prebuild: NSBonjourServices/);
|
||||
} finally {
|
||||
rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test('requires the local EAS plugin executable rather than its package directory', () => {
|
||||
const root = mkdtempSync(join(tmpdir(), 'sauci-eas-plugin-'));
|
||||
const executable = join(root, 'bin-run');
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
import {
|
||||
hasSeenMatchesTutorial,
|
||||
markMatchesTutorialSeen,
|
||||
resetMatchesTutorial,
|
||||
} from "@/lib/matchesTutorialSeen";
|
||||
|
||||
jest.mock("expo-secure-store", () => ({
|
||||
getItemAsync: jest.fn(),
|
||||
}));
|
||||
|
||||
describe("matchesTutorialSeen", () => {
|
||||
beforeEach(async () => {
|
||||
await AsyncStorage.clear();
|
||||
jest.mocked(SecureStore.getItemAsync).mockReset();
|
||||
jest.mocked(SecureStore.getItemAsync).mockResolvedValue(null);
|
||||
});
|
||||
|
||||
it("persists a dismissal for the signed-in account", async () => {
|
||||
await markMatchesTutorialSeen("user-1");
|
||||
|
||||
await expect(hasSeenMatchesTutorial("user-1")).resolves.toBe(true);
|
||||
});
|
||||
|
||||
it("does not dismiss the tutorial for another account on the same device", async () => {
|
||||
await markMatchesTutorialSeen("user-1");
|
||||
|
||||
await expect(hasSeenMatchesTutorial("user-2")).resolves.toBe(false);
|
||||
});
|
||||
|
||||
it("migrates an existing legacy dismissal into durable account storage", async () => {
|
||||
jest.mocked(SecureStore.getItemAsync).mockResolvedValue("true");
|
||||
|
||||
await expect(hasSeenMatchesTutorial("user-1")).resolves.toBe(true);
|
||||
await expect(AsyncStorage.getItem("matches_tutorial_seen_user-1")).resolves.toBe("true");
|
||||
});
|
||||
|
||||
it("lets the development reset show the tutorial for the current account again", async () => {
|
||||
await markMatchesTutorialSeen("user-1");
|
||||
await resetMatchesTutorial("user-1");
|
||||
|
||||
await expect(hasSeenMatchesTutorial("user-1")).resolves.toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -223,7 +223,8 @@ export function ProfileScreen() {
|
||||
label="Reset Matches Tutorial"
|
||||
description="Show the tutorial again"
|
||||
onPress={async () => {
|
||||
await resetMatchesTutorial();
|
||||
if (!user?.id) return;
|
||||
await resetMatchesTutorial(user.id);
|
||||
Alert.alert("Success", "Matches tutorial has been reset.");
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,51 +1,70 @@
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as SecureStore from "expo-secure-store";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
const STORAGE_KEY = "matches_tutorial_seen";
|
||||
const STORAGE_KEY_PREFIX = "matches_tutorial_seen";
|
||||
const LEGACY_STORAGE_KEY = "matches_tutorial_seen";
|
||||
|
||||
async function getStorage(): Promise<boolean> {
|
||||
const buildKey = (userId: string): string => `${STORAGE_KEY_PREFIX}_${userId}`;
|
||||
|
||||
async function getStorage(userId: string): Promise<boolean> {
|
||||
try {
|
||||
let data: string | null = null;
|
||||
const key = buildKey(userId);
|
||||
|
||||
if (Platform.OS === "web") {
|
||||
if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
|
||||
data = window.localStorage.getItem(STORAGE_KEY);
|
||||
return window.localStorage.getItem(key) === "true";
|
||||
}
|
||||
} else {
|
||||
data = await SecureStore.getItemAsync(STORAGE_KEY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return data === "true";
|
||||
const storedValue = await AsyncStorage.getItem(key);
|
||||
if (storedValue !== null) {
|
||||
return storedValue === "true";
|
||||
}
|
||||
|
||||
// Keep dismissals made before the account-scoped AsyncStorage key was
|
||||
// introduced. Future reads use the durable app storage key above.
|
||||
const legacyValue = await SecureStore.getItemAsync(LEGACY_STORAGE_KEY);
|
||||
if (legacyValue === "true") {
|
||||
await AsyncStorage.setItem(key, "true");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (error) {
|
||||
console.error("Error reading matches tutorial state:", error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function setStorage(seen: boolean): Promise<void> {
|
||||
async function setStorage(userId: string, seen: boolean): Promise<void> {
|
||||
try {
|
||||
const data = seen ? "true" : "false";
|
||||
const key = buildKey(userId);
|
||||
|
||||
if (Platform.OS === "web") {
|
||||
if (typeof window !== "undefined" && typeof window.localStorage !== "undefined") {
|
||||
window.localStorage.setItem(STORAGE_KEY, data);
|
||||
window.localStorage.setItem(key, data);
|
||||
}
|
||||
} else {
|
||||
await SecureStore.setItemAsync(STORAGE_KEY, data);
|
||||
await AsyncStorage.setItem(key, data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error saving matches tutorial state:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function hasSeenMatchesTutorial(): Promise<boolean> {
|
||||
return getStorage();
|
||||
/** The Matches tutorial is shown at most once per signed-in account. */
|
||||
export async function hasSeenMatchesTutorial(userId: string): Promise<boolean> {
|
||||
return getStorage(userId);
|
||||
}
|
||||
|
||||
export async function markMatchesTutorialSeen(): Promise<void> {
|
||||
await setStorage(true);
|
||||
export async function markMatchesTutorialSeen(userId: string): Promise<void> {
|
||||
await setStorage(userId, true);
|
||||
}
|
||||
|
||||
export async function resetMatchesTutorial(): Promise<void> {
|
||||
await setStorage(false);
|
||||
export async function resetMatchesTutorial(userId: string): Promise<void> {
|
||||
await setStorage(userId, false);
|
||||
}
|
||||
@@ -28,5 +28,10 @@
|
||||
"postcss": "^8.4.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-linux-x64-gnu": "15.5.24",
|
||||
"@next/swc-linux-x64-musl": "15.5.24",
|
||||
"@next/swc-darwin-arm64": "15.5.24"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
# Dependency and lockfile discipline
|
||||
|
||||
## Two npm realities
|
||||
|
||||
CI runners and the API Docker image use the node version pinned in
|
||||
`.nvmrc` (node 20.19.4 with npm 10.8.2). A developer machine can run a newer
|
||||
npm (for example npm 11). npm 10 and npm 11 resolve wildcard or range
|
||||
dependencies differently at the same place in the dependency tree, and each
|
||||
npm's platform-optional binary selection is not portable to a lockfile
|
||||
regenerated by the other npm. A lockfile that passes `npm ci` under one npm
|
||||
major version can fail it under the other with either an "Invalid: lock
|
||||
file's ... does not satisfy" error or missing platform-optional binaries
|
||||
(for example `@next/swc-linux-x64-gnu` breaking `next build`,
|
||||
`@rollup/rollup-linux-x64-gnu` breaking the API Docker `tsup` build, or a
|
||||
missing `lightningcss` variant breaking local `npm ci`).
|
||||
|
||||
## Pin wildcard-range dependencies with root overrides
|
||||
|
||||
When a transitive dependency declares a wildcard or wide range (for example
|
||||
`react-native-worklets` depending on `@react-native/metro-config: "*"`), pin
|
||||
the exact version the app needs in the root `package.json` `overrides` block
|
||||
rather than leaving it to whichever npm resolved the lockfile last:
|
||||
|
||||
```json
|
||||
"overrides": {
|
||||
"rollup": "4.54.0",
|
||||
"react-native": "0.85.3",
|
||||
"expo": "~56.0.0",
|
||||
"@react-native/metro-config": "0.85.3"
|
||||
}
|
||||
```
|
||||
|
||||
## Pin platform-optional binaries that must travel with the framework version
|
||||
|
||||
`apps/web/package.json` pins the `@next/swc` linux and darwin binaries as
|
||||
direct `optionalDependencies` so npm does not have to infer them per
|
||||
platform:
|
||||
|
||||
```json
|
||||
"optionalDependencies": {
|
||||
"@next/swc-linux-x64-gnu": "15.5.24",
|
||||
"@next/swc-linux-x64-musl": "15.5.24",
|
||||
"@next/swc-darwin-arm64": "15.5.24"
|
||||
}
|
||||
```
|
||||
|
||||
These versions must be bumped together with any `next` version bump, or the
|
||||
pinned binaries will drift from the framework version and `npm ci` or
|
||||
`next build` can fail on the platform that needs the stale binary.
|
||||
|
||||
## Validate a regenerated lockfile both ways
|
||||
|
||||
After changing `overrides` or any dependency version, regenerate
|
||||
`package-lock.json` and validate it under both npm majors before committing:
|
||||
|
||||
```bash
|
||||
# Local npm (matches this machine's npm major)
|
||||
npm ci
|
||||
npm run verify:fast
|
||||
|
||||
# The CI/Docker npm major, emulated on Apple Silicon
|
||||
docker run --rm --platform linux/amd64 -v "$PWD:/repo" -w /repo node:20.19.4 npm ci
|
||||
```
|
||||
|
||||
The `--platform linux/amd64` flag is mandatory on Apple Silicon: without it,
|
||||
Docker runs the arm64 image and the platform-binary check proves nothing.
|
||||
|
||||
## After any bypassed push
|
||||
|
||||
Pushes to `staging` bypass required status checks. After any such push, check
|
||||
`gh run list --branch staging` to confirm CI is actually green rather than
|
||||
assuming it ran and passed.
|
||||
|
||||
Do not pipe `npm` commands through `tail` when diagnosing a lockfile or build
|
||||
failure; it can swallow the command's exit code and the detail needed to find
|
||||
the root cause.
|
||||
@@ -8,6 +8,7 @@ historical notes. Agents should load only the section relevant to their task.
|
||||
- [System architecture](architecture/system.md)
|
||||
- [Client data freshness](architecture/client-data-freshness.md)
|
||||
- [Local full-stack development](development/local-stack.md)
|
||||
- [Dependency and lockfile discipline](development/dependencies.md)
|
||||
- [Testing strategy](testing/strategy.md)
|
||||
- [Database migration safety](operations/database-migrations.md)
|
||||
- [Backend deployment and branching](operations/backend-deployments.md)
|
||||
|
||||
@@ -14,10 +14,14 @@ not deploy the retired Supabase data plane.
|
||||
| `master` | frozen legacy default | none | none |
|
||||
|
||||
Normal feature pull requests target `staging`. After CI and authenticated staging
|
||||
acceptance pass, open a promotion pull request from `staging` to `main`. Do not
|
||||
add production-only commits to `main`: production should run the exact commit
|
||||
already exercised in staging. Direct pushes to either deployment branch are for
|
||||
explicit incident recovery only.
|
||||
acceptance pass, open a promotion pull request from `staging` to `main`. Prefer
|
||||
that route: production then runs the exact commit already exercised in staging.
|
||||
|
||||
When production needs a change that cannot wait for the next promotion, open a
|
||||
pull request into `main` from a `hotfix/*` or `release/*` branch. CI enforces
|
||||
that naming so a direct-to-main change is always deliberate and visible. Land
|
||||
the same commit on `staging` too, or the next promotion will revert it. Direct
|
||||
pushes to either deployment branch remain blocked by branch protection.
|
||||
|
||||
Each Dokploy Compose application is connected to `jjbrunton/Sauci`, watches its
|
||||
single branch with push-triggered automatic deployment, and uses
|
||||
|
||||
@@ -249,6 +249,23 @@ and dependency installation failures occur before native compilation: fix and
|
||||
preflight those inputs without starting another build. Make one meaningful build
|
||||
per newly proven input state.
|
||||
|
||||
Before starting: confirm `eas` is installed and on PATH (scripts call bare
|
||||
`eas`); explicitly export `ANDROID_HOME`, `ANDROID_SDK_ROOT`, and `JAVA_HOME`
|
||||
(JDK 17) rather than relying on a shell profile, because non-interactive shells
|
||||
used for automation do not load it ("SDK location not found" otherwise); ensure
|
||||
`EAS_LOCAL_BUILD_WORKINGDIR` does not exist or is empty ("Workingdir is not
|
||||
empty" otherwise); and run every command from `apps/mobile`. Capture the full
|
||||
build log to a file; do not pipe it through `tail`, which drops the detail
|
||||
needed to diagnose a failure.
|
||||
|
||||
After a successful iOS build, EAS auto-increment updates both app and widget
|
||||
Info.plists but not the widget target's `CURRENT_PROJECT_VERSION` in the
|
||||
pbxproj, so `release:preflight` fails until it is synced to the new build
|
||||
number (for example `sed -i '' 's/CURRENT_PROJECT_VERSION = 46;/CURRENT_PROJECT_VERSION = 47;/' ios/Sauci.xcodeproj/project.pbxproj`
|
||||
for both Debug and Release). If native dependencies changed, also sync
|
||||
`ios/Podfile.lock` from the successful build's working directory: the archive's
|
||||
`pod install` resolution is authoritative when local CocoaPods is broken.
|
||||
|
||||
Report provider progress by phase: packaging, native compilation, submission
|
||||
queue, or store processing. Do not describe every failure as a rebuild.
|
||||
|
||||
@@ -292,6 +309,24 @@ verify it, and commit it before starting the release from a clean worktree. Use
|
||||
5.x, a non-clean prebuild against an already-generated iOS project fails while
|
||||
updating the widget's Xcode target.
|
||||
|
||||
**After native regeneration:** `expo prebuild --clean` can silently regress
|
||||
checked-in native invariants (confirmed during the SDK 54 to 56 upgrade). Before
|
||||
committing a regenerated project:
|
||||
|
||||
- Diff pbxproj signing and identity keys (PRODUCT_BUNDLE_IDENTIFIER,
|
||||
CODE_SIGN_ENTITLEMENTS) against the last release tag; apple-targets can derive
|
||||
a widget's bundle identifier from its folder name instead of the pinned config.
|
||||
- Semantic-diff Info.plist and entitlements files against the last release tag;
|
||||
prebuild can reintroduce dev-launcher-only keys (NSBonjourServices,
|
||||
NSLocalNetworkUsageDescription, RCTMetroPort) and drop widget entitlements.
|
||||
- Check android/gradle.properties for a reset `org.gradle.jvmargs` (prebuild
|
||||
resets it to the stock -Xmx2048m/512m, which OOMs release Kotlin/CMake tasks).
|
||||
- Run `npm run release:preflight`; it enforces the Android manifest media
|
||||
permission removal and rejects the dev-launcher-only Info.plist keys.
|
||||
- Treat `expo-doctor` unmaintained-package warnings as release blockers on an
|
||||
SDK upgrade: a package absent from the new SDK's bundledNativeModules can fail
|
||||
the iOS archive with no compatible release available.
|
||||
|
||||
**Out of memory:**
|
||||
```bash
|
||||
# Increase Gradle memory
|
||||
|
||||
@@ -87,9 +87,12 @@ Before the first deployment, provide:
|
||||
5. A rollback and restore point before any migrated production data is imported.
|
||||
6. A separately generated `MEDIA_SIGNING_SECRET` (at least 32 characters) and
|
||||
the HTTPS API origin as `MEDIA_PUBLIC_BASE_URL`.
|
||||
7. The public web origin is fixed to `https://sauci.app` by
|
||||
`CORS_ALLOWED_ORIGINS` in the Compose contract. Do not broaden it without a
|
||||
reviewed browser client requirement.
|
||||
7. Browser origins are fixed by `CORS_ALLOWED_ORIGINS` in the Compose contract:
|
||||
`https://sauci.app` (public web) and `https://manage.sauci.app` (admin
|
||||
console, which calls `/v1/admin/*` with a bearer token). Do not broaden the
|
||||
list without a reviewed browser client requirement, and add any new admin
|
||||
host here rather than as a Dokploy override, so the allowlist stays
|
||||
reviewable in git.
|
||||
8. A non-production hosted Auth project and disposable, onboarding-complete test
|
||||
identities mapped into the staging database for authenticated mobile acceptance.
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ x-common-environment: &common-environment
|
||||
x-api-environment: &api-environment
|
||||
<<: *common-environment
|
||||
PORT: 3003
|
||||
CORS_ALLOWED_ORIGINS: https://sauci.app
|
||||
# https://manage.sauci.app is the admin console; it calls /v1/admin/* from the browser.
|
||||
CORS_ALLOWED_ORIGINS: https://sauci.app,https://manage.sauci.app
|
||||
DATABASE_POOL_MAX: ${API_DATABASE_POOL_MAX:-10}
|
||||
DATABASE_POOL_IDLE_TIMEOUT_MS: ${DATABASE_POOL_IDLE_TIMEOUT_MS:-30000}
|
||||
DATABASE_POOL_CONNECTION_TIMEOUT_MS: ${DATABASE_POOL_CONNECTION_TIMEOUT_MS:-10000}
|
||||
|
||||
Generated
+128
-141
@@ -311,10 +311,36 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"apps/mobile/node_modules/@shopify/react-native-skia": {
|
||||
"version": "2.6.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvaskit-wasm": "0.41.0",
|
||||
"react-native-skia-android": "150.0.0",
|
||||
"react-native-skia-apple-ios": "150.0.0",
|
||||
"react-native-skia-apple-macos": "150.0.0",
|
||||
"react-native-skia-apple-tvos": "150.0.0",
|
||||
"react-reconciler": "0.31.0"
|
||||
},
|
||||
"bin": {
|
||||
"setup-skia-web": "scripts/setup-canvaskit.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=19.0",
|
||||
"react-native": ">=0.78",
|
||||
"react-native-reanimated": ">=3.19.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native-reanimated": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"apps/mobile/node_modules/@types/react": {
|
||||
"version": "19.2.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
|
||||
"integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -358,6 +384,11 @@
|
||||
"postcss": "^8.4.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"typescript": "^5.3.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "15.5.24",
|
||||
"@next/swc-linux-x64-gnu": "15.5.24",
|
||||
"@next/swc-linux-x64-musl": "15.5.24"
|
||||
}
|
||||
},
|
||||
"apps/web/node_modules/eslint-config-next": {
|
||||
@@ -2440,7 +2471,6 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2662,7 +2692,6 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2697,7 +2726,6 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2732,7 +2760,6 @@
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -4876,8 +4903,6 @@
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
|
||||
"integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/utils": "^0.2.12"
|
||||
@@ -4885,8 +4910,6 @@
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "1.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
|
||||
"integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.8.0",
|
||||
@@ -4895,8 +4918,6 @@
|
||||
},
|
||||
"node_modules/@floating-ui/react-dom": {
|
||||
"version": "2.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz",
|
||||
"integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.8.0"
|
||||
@@ -4908,8 +4929,6 @@
|
||||
},
|
||||
"node_modules/@floating-ui/utils": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
|
||||
"integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@grpc/grpc-js": {
|
||||
@@ -5732,6 +5751,44 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "15.5.24",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.24.tgz",
|
||||
"integrity": "sha512-7dwtlhr0SLndqTG1z9ncRkbJswDZiKWlxzFyXDvJ2RDZRDRHp8zyMJ4D9UH/FgnQeXxxB6gZy2pMcIUoNKQ4pA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "15.5.24",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.24.tgz",
|
||||
"integrity": "sha512-kGZxM+WhkYs0276lFrMkj7PRtXT3Btp6cwvfSO/cCVLxJJttB5Ccnl2niaCgUja8HgSbEVnMHpg3FJWoOJ9e/g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@noble/ciphers": {
|
||||
"version": "1.3.0",
|
||||
"dev": true,
|
||||
@@ -5991,8 +6048,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz",
|
||||
"integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.10"
|
||||
@@ -6040,8 +6095,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.15.tgz",
|
||||
"integrity": "sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
@@ -6092,8 +6145,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-dialog": {
|
||||
"version": "1.1.23",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.23.tgz",
|
||||
"integrity": "sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
@@ -6142,8 +6193,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz",
|
||||
"integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
@@ -6209,8 +6258,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz",
|
||||
"integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.5",
|
||||
@@ -6271,8 +6318,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-menu": {
|
||||
"version": "2.1.24",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.24.tgz",
|
||||
"integrity": "sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
@@ -6311,8 +6356,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz",
|
||||
"integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
@@ -6343,8 +6386,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz",
|
||||
"integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.10",
|
||||
@@ -6367,8 +6408,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-presence": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz",
|
||||
"integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-use-layout-effect": "1.1.4"
|
||||
@@ -6390,8 +6429,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz",
|
||||
"integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.3.3"
|
||||
@@ -6413,8 +6450,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-roving-focus": {
|
||||
"version": "1.1.19",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.19.tgz",
|
||||
"integrity": "sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
@@ -6551,8 +6586,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs": {
|
||||
"version": "1.1.21",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.21.tgz",
|
||||
"integrity": "sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.7",
|
||||
@@ -6700,8 +6733,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-use-rect": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz",
|
||||
"integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/rect": "1.1.3"
|
||||
@@ -6734,8 +6765,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-visually-hidden": {
|
||||
"version": "1.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.11.tgz",
|
||||
"integrity": "sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.1.10"
|
||||
@@ -6757,8 +6786,6 @@
|
||||
},
|
||||
"node_modules/@radix-ui/rect": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz",
|
||||
"integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@react-native-async-storage/async-storage": {
|
||||
@@ -7399,6 +7426,9 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7413,6 +7443,9 @@
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7427,6 +7460,9 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7440,6 +7476,9 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7454,6 +7493,9 @@
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7468,6 +7510,9 @@
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7482,6 +7527,9 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7496,6 +7544,9 @@
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7510,6 +7561,9 @@
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7524,6 +7578,9 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7537,6 +7594,9 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7651,36 +7711,6 @@
|
||||
"resolved": "apps/web",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@shopify/react-native-skia": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/@shopify/react-native-skia/-/react-native-skia-2.6.9.tgz",
|
||||
"integrity": "sha512-x+16pwmnW9ZQKy4/B7Npc1b5Qli9vZCAiWn9uU58tLylJity8qV+fUb4gf6Qolqsw/u6FPaNTaAnHVCvu3LnRw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"canvaskit-wasm": "0.41.0",
|
||||
"react-native-skia-android": "150.0.0",
|
||||
"react-native-skia-apple-ios": "150.0.0",
|
||||
"react-native-skia-apple-macos": "150.0.0",
|
||||
"react-native-skia-apple-tvos": "150.0.0",
|
||||
"react-reconciler": "0.31.0"
|
||||
},
|
||||
"bin": {
|
||||
"setup-skia-web": "scripts/setup-canvaskit.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=19.0",
|
||||
"react-native": ">=0.78",
|
||||
"react-native-reanimated": ">=3.19.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-native": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native-reanimated": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.5",
|
||||
"license": "BSD-3-Clause",
|
||||
@@ -7778,6 +7808,9 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7792,6 +7825,9 @@
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7806,6 +7842,9 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -7820,6 +7859,9 @@
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -8480,8 +8522,6 @@
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.1.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz",
|
||||
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
@@ -8489,8 +8529,6 @@
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "19.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.11.tgz",
|
||||
"integrity": "sha512-3BKc/yGdNTYQVVw4idqHtSOcFsgGuBbMveKCOgF8wQ5QtrYOc3jDIlzg3jef04zcXFIHLelyGlj0T+BJ8+KN+w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
@@ -12349,7 +12387,6 @@
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12367,7 +12404,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12385,7 +12421,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12403,7 +12438,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12421,7 +12455,6 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12439,7 +12472,6 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12457,7 +12489,6 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12475,7 +12506,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12493,7 +12523,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12511,7 +12540,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12529,7 +12557,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12547,7 +12574,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12565,7 +12591,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12583,7 +12608,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12601,7 +12625,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12619,7 +12642,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12637,7 +12659,6 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12655,7 +12676,6 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12673,7 +12693,6 @@
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12691,7 +12710,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12709,7 +12727,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -12727,7 +12744,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -13731,8 +13747,6 @@
|
||||
},
|
||||
"node_modules/expo-audio": {
|
||||
"version": "56.0.13",
|
||||
"resolved": "https://registry.npmjs.org/expo-audio/-/expo-audio-56.0.13.tgz",
|
||||
"integrity": "sha512-pfBmT/8OYbhrb37ECk+fC1EstLBFxMTioF4uZrAEeOj3uCgjproj1qYmkpsQLJIoEOMPSIw1iSfBEMl10v1DDA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
@@ -14718,8 +14732,6 @@
|
||||
},
|
||||
"node_modules/expo-video": {
|
||||
"version": "56.1.4",
|
||||
"resolved": "https://registry.npmjs.org/expo-video/-/expo-video-56.1.4.tgz",
|
||||
"integrity": "sha512-8mXZOnb7ZsWneDlcnRf0M2Ox9eb5dGnNiGiCkj9bwLPY+3jM2Pc1t5ymNUuhw8lSpT/rOnE0J0/81Y3+0k2Zcw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
@@ -18708,6 +18720,9 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -18728,6 +18743,9 @@
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -18748,6 +18766,9 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -18768,6 +18789,9 @@
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -20792,7 +20816,6 @@
|
||||
},
|
||||
"node_modules/playwright/node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
@@ -21570,26 +21593,18 @@
|
||||
},
|
||||
"node_modules/react-native-skia-android": {
|
||||
"version": "150.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-skia-android/-/react-native-skia-android-150.0.0.tgz",
|
||||
"integrity": "sha512-Eiv52NT6Y1eB8ZGmM8Uz01SQ+U8OAaDy2WSpPQQCpvfCWid1ufpsh1YhWVGrW55IJdJWm6/8DJTDEyQsJLH5ew==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-skia-apple-ios": {
|
||||
"version": "150.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-skia-apple-ios/-/react-native-skia-apple-ios-150.0.0.tgz",
|
||||
"integrity": "sha512-RrJHQEcsPUN8i/KqBwqEIQ6MmbMvL3nWtlJPQ+K5n6Nw4SF0W9VhL2yf2/jguX0WWydMyR5R4pSrJprfWFBMAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-skia-apple-macos": {
|
||||
"version": "150.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-skia-apple-macos/-/react-native-skia-apple-macos-150.0.0.tgz",
|
||||
"integrity": "sha512-CBqQvaWRl5U+jBjUPbTGrf3g6M0GM7S0g6Ia6QK91K2G5xkMwrzs9l03zheYSdLzTtRCnW+Tkyws7K4whDJc3g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-skia-apple-tvos": {
|
||||
"version": "150.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-skia-apple-tvos/-/react-native-skia-apple-tvos-150.0.0.tgz",
|
||||
"integrity": "sha512-W1oDsSGK+nRvPu2/b1tUWvOorbYTjhJ3SLWDPAIWH43mSgfdn3zws3AZttfJO81Qmqpf3blJrFCoCzASRdi7qg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-native-svg": {
|
||||
@@ -21723,8 +21738,6 @@
|
||||
},
|
||||
"node_modules/react-native/node_modules/@react-native/virtualized-lists": {
|
||||
"version": "0.85.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.85.3.tgz",
|
||||
"integrity": "sha512-dsCjI//OIPEUJMyNHp4l7zNLVjCx7bcaRUceOCkU+IB17hkbtbGWvi7HjGFSzy7FJGmS/MOlcfpb72xXiy1Oig==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"invariant": "^2.2.4",
|
||||
@@ -24528,7 +24541,6 @@
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24546,7 +24558,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24564,7 +24575,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24582,7 +24592,6 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24598,7 +24607,6 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24616,7 +24624,6 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24634,7 +24641,6 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24652,7 +24658,6 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24670,7 +24675,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24688,7 +24692,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24706,7 +24709,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24724,7 +24726,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24742,7 +24743,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24760,7 +24760,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24778,7 +24777,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24796,7 +24794,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24814,7 +24811,6 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24832,7 +24828,6 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24850,7 +24845,6 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24868,7 +24862,6 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24886,7 +24879,6 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24904,7 +24896,6 @@
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24922,7 +24913,6 @@
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24940,7 +24930,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24958,7 +24947,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -24976,7 +24964,6 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
|
||||
+2
-1
@@ -60,7 +60,8 @@
|
||||
"overrides": {
|
||||
"rollup": "4.54.0",
|
||||
"react-native": "0.85.3",
|
||||
"expo": "~56.0.0"
|
||||
"expo": "~56.0.0",
|
||||
"@react-native/metro-config": "0.85.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-linux-arm64-musl": "4.54.0",
|
||||
|
||||
Reference in new issue
Block a user