08eadd8149
The single native pass resolved [".ios", ".android", ".native", ""], which models a platform that does not exist - on iOS Metro never falls back to .android files and vice versa. Replace it with tsconfig.check.ios.json and tsconfig.check.android.json, each mirroring Metro's real resolution order for its platform, alongside the existing web pass. pnpm typecheck now runs all three, and the lint workflow matrix runs them as separate jobs. The ambient check shims in src/platform are now excluded from passes they aren't written for (previously the web shims were silently included in the native pass via the "src" include glob), and a new Android-pass shim pins react-native-device-attest to its platform-neutral base class, whose Android variant omits the iOS-only getDeviceCheckToken static. The Android pass surfaced a real bug: Referrer.getReferrerInfo() is async on Android (the Play referrer API only exposes a promise) but sync on iOS/web, and the shared callers used it synchronously - so on Android the deepLink:referrerReceived metric fired with a Promise instead of data. The API is now uniformly promise-returning and the callers await it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BCuMKXWHuyGoNhTVAHBMyk
376 lines
14 KiB
JSON
376 lines
14 KiB
JSON
{
|
|
"name": "bsky.app",
|
|
"version": "1.128.0",
|
|
"private": true,
|
|
"engines": {
|
|
"node": ">=24.18.0"
|
|
},
|
|
"devEngines": {
|
|
"packageManager": {
|
|
"name": "pnpm",
|
|
"version": "11.13.1",
|
|
"onFail": "warn"
|
|
},
|
|
"runtime": {
|
|
"name": "node",
|
|
"version": "^24.18.0",
|
|
"onFail": "download"
|
|
}
|
|
},
|
|
"expo": {
|
|
"autolinking": {
|
|
"android": {
|
|
"buildFromSource": [
|
|
"expo-notifications",
|
|
"expo-haptics",
|
|
"expo-media-library",
|
|
"expo-image-picker"
|
|
]
|
|
}
|
|
},
|
|
"install": {
|
|
"exclude": [
|
|
"react-native-reanimated",
|
|
"@sentry/react-native",
|
|
"react-native-pager-view"
|
|
]
|
|
}
|
|
},
|
|
"scripts": {
|
|
"prepare": "is-ci || husky",
|
|
"postinstall": "pnpm intl:compile-if-needed",
|
|
"prebuild": "EXPO_NO_GIT_STATUS=1 expo prebuild --clean",
|
|
"android": "expo run:android",
|
|
"android:prod": "expo run:android --variant release",
|
|
"android:profile": "BSKY_PROFILE=1 expo run:android --variant release",
|
|
"ios": "expo run:ios",
|
|
"web": "expo start --web",
|
|
"use-build-number": "./scripts/useBuildNumberEnv.sh",
|
|
"use-build-number-with-bump": "./scripts/useBuildNumberEnvWithBump.sh",
|
|
"build-web": "expo export:web && node ./scripts/post-web-build.js",
|
|
"build-all": "pnpm intl:build && pnpm use-build-number-with-bump eas build --platform all",
|
|
"build-ios": "pnpm use-build-number-with-bump eas build -p ios",
|
|
"build-android": "pnpm use-build-number-with-bump eas build -p android",
|
|
"build": "pnpm use-build-number-with-bump eas build",
|
|
"build-embed": "cd bskyembed && pnpm build && pnpm build-snippet && cd .. && node ./scripts/post-embed-build.js",
|
|
"start": "expo start --dev-client",
|
|
"start:prod": "expo start --dev-client --no-dev --minify",
|
|
"test": "NODE_ENV=test jest --forceExit --testTimeout=20000 --bail",
|
|
"test-watch": "NODE_ENV=test jest --watchAll",
|
|
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
|
|
"test-coverage": "NODE_ENV=test jest --coverage",
|
|
"lint": "oxlint --quiet src modules",
|
|
"lint-native": "swiftlint ./modules && ktlint ./modules",
|
|
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
|
|
"typecheck": "pnpm run typecheck:ios && pnpm run typecheck:android && pnpm run typecheck:web",
|
|
"typecheck:ios": "tsgo --project ./tsconfig.check.ios.json",
|
|
"typecheck:android": "tsgo --project ./tsconfig.check.android.json",
|
|
"typecheck:web": "tsgo --project ./tsconfig.check.web.json",
|
|
"e2e:mock-server": "cd dev-env && pnpm start",
|
|
"e2e:build": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",
|
|
"e2e:build-android": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:android",
|
|
"e2e:start": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo start -c",
|
|
"e2e:run": "maestro test",
|
|
"perf:test": "NODE_ENV=test maestro test",
|
|
"perf:test:run": "NODE_ENV=test maestro test __e2e__/perf-test.yml",
|
|
"perf:test:measure": "NODE_ENV=test flashlight test --bundleId xyz.blueskyweb.app --testCommand \"pnpm perf:test\" --duration 150000 --resultsFilePath .perf/results.json",
|
|
"perf:test:results": "NODE_ENV=test flashlight report .perf/results.json",
|
|
"perf:measure": "NODE_ENV=test flashlight measure",
|
|
"intl:build": "pnpm intl:extract:all && pnpm intl:compile",
|
|
"intl:extract": "lingui extract --clean --locale en",
|
|
"intl:extract:all": "lingui extract --clean",
|
|
"intl:compile": "lingui compile",
|
|
"intl:compile-if-needed": "is-ci || [ -f src/locale/locales/en/messages.ts ] || pnpm intl:compile",
|
|
"intl:pull": "crowdin download translations --verbose -b main",
|
|
"intl:push": "crowdin push translations --verbose -b main",
|
|
"intl:push-sources": "crowdin push sources --verbose -b main",
|
|
"intl:release": "pnpm intl:pull && pnpm intl:extract:all",
|
|
"nuke": "rm -rf ./node_modules && rm -rf ./ios && rm -rf ./android",
|
|
"update-extensions": "bash scripts/updateExtensions.sh",
|
|
"export": "expo export --dump-sourcemap && pnpm upload-native-sourcemaps",
|
|
"upload-native-sourcemaps": "pnpm exec sentry-expo-upload-sourcemaps dist",
|
|
"make-deploy-bundle": "bash scripts/bundleUpdate.sh",
|
|
"generate-webpack-stats-file": "EXPO_PUBLIC_GENERATE_STATS=1 pnpm build-web",
|
|
"open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 pnpm build-web",
|
|
"icons:optimize": "svgo -f ./assets/icons",
|
|
"prettier": "prettier --check ."
|
|
},
|
|
"dependencies": {
|
|
"@atproto/api": "0.20.28",
|
|
"@atproto/common-web": "0.5.6",
|
|
"@atproto/syntax": "0.7.2",
|
|
"@bitdrift/react-native": "^0.6.8",
|
|
"@braintree/sanitize-url": "^6.0.2",
|
|
"@bsky.app/alf": "^0.1.14",
|
|
"@bsky.app/expo-dynamic-app-icon": "^1.8.5",
|
|
"@bsky.app/expo-guess-language": "^0.2.8",
|
|
"@bsky.app/expo-image-crop-tool": "^0.5.1",
|
|
"@bsky.app/expo-scroll-edge-effect": "^0.1.4",
|
|
"@bsky.app/expo-translate-text": "^0.2.9",
|
|
"@bsky.app/peek-menu": "^0.3.1",
|
|
"@bsky.app/react-native-mmkv": "2.12.5",
|
|
"@bsky.app/sift": "^0.3.9",
|
|
"@bsky.app/tapper": "^0.6.1",
|
|
"@bsky.app/video": "0.3.6",
|
|
"@emoji-mart/data": "^1.2.1",
|
|
"@emoji-mart/react": "^1.1.1",
|
|
"@expo/html-elements": "^0.12.5",
|
|
"@expo/webpack-config": "^19.0.1",
|
|
"@floating-ui/dom": "^1.6.3",
|
|
"@floating-ui/react-dom": "^2.0.8",
|
|
"@formatjs/intl-displaynames": "^7.3.9",
|
|
"@formatjs/intl-locale": "^5.3.8",
|
|
"@formatjs/intl-numberformat": "^9.3.10",
|
|
"@formatjs/intl-pluralrules": "^6.3.9",
|
|
"@growthbook/growthbook": "^1.6.5",
|
|
"@growthbook/growthbook-react": "^1.6.5",
|
|
"@ipld/dag-cbor": "^9.2.7",
|
|
"@lingui/core": "^5.9.2",
|
|
"@lingui/react": "^5.9.2",
|
|
"@react-native-async-storage/async-storage": "2.2.0",
|
|
"@react-navigation/bottom-tabs": "^7.15.5",
|
|
"@react-navigation/native": "^7.1.33",
|
|
"@react-navigation/native-stack": "^7.14.4",
|
|
"@sentry/react-native": "~8.18.0",
|
|
"@tanstack/query-async-storage-persister": "^5.96.2",
|
|
"@tanstack/react-query": "^5.96.2",
|
|
"@tanstack/react-query-persist-client": "^5.96.2",
|
|
"@tiptap/core": "^2.9.1",
|
|
"@tiptap/extension-document": "^2.9.1",
|
|
"@tiptap/extension-hard-break": "^2.9.1",
|
|
"@tiptap/extension-history": "^2.9.1",
|
|
"@tiptap/extension-mention": "^2.9.1",
|
|
"@tiptap/extension-paragraph": "^2.9.1",
|
|
"@tiptap/extension-placeholder": "^2.9.1",
|
|
"@tiptap/extension-text": "^2.9.1",
|
|
"@tiptap/pm": "^2.9.1",
|
|
"@tiptap/react": "^2.9.1",
|
|
"@tiptap/suggestion": "^2.9.1",
|
|
"@types/invariant": "^2.2.37",
|
|
"@types/lodash.throttle": "^4.1.9",
|
|
"@types/node": "^24.12.2",
|
|
"array.prototype.findlast": "^1.2.3",
|
|
"babel-plugin-transform-remove-console": "^6.9.4",
|
|
"bcp-47": "^2.1.0",
|
|
"bcp-47-match": "^2.0.3",
|
|
"date-fns": "^4.4.0",
|
|
"email-validator": "^2.0.4",
|
|
"emoji-mart": "^5.6.0",
|
|
"emoji-regex": "^10.4.0",
|
|
"eventemitter3": "^5.0.1",
|
|
"expo": "54.0.34",
|
|
"expo-age-range": "0.2.18",
|
|
"expo-application": "~7.0.8",
|
|
"expo-blur": "~15.0.8",
|
|
"expo-build-properties": "~1.0.10",
|
|
"expo-camera": "~17.0.10",
|
|
"expo-clipboard": "~8.0.8",
|
|
"expo-contacts": "^15.0.10",
|
|
"expo-dev-client": "~6.0.20",
|
|
"expo-device": "~8.0.10",
|
|
"expo-file-system": "~19.0.21",
|
|
"expo-font": "~14.0.11",
|
|
"expo-glass-effect": "55.0.8",
|
|
"expo-haptics": "~15.0.8",
|
|
"expo-image": "~3.0.11",
|
|
"expo-image-manipulator": "~14.0.8",
|
|
"expo-image-picker": "~17.0.10",
|
|
"expo-intent-launcher": "~13.0.8",
|
|
"expo-keep-awake": "~15.0.8",
|
|
"expo-linear-gradient": "~15.0.8",
|
|
"expo-linking": "~8.0.11",
|
|
"expo-localization": "~17.0.8",
|
|
"expo-location": "~19.0.8",
|
|
"expo-media-library": "~18.2.1",
|
|
"expo-notifications": "~0.32.17",
|
|
"expo-paste-input": "^0.2.1",
|
|
"expo-privacy-sensitive": "^0.1.0",
|
|
"expo-screen-orientation": "~9.0.8",
|
|
"expo-sharing": "~14.0.8",
|
|
"expo-sms": "^14.0.7",
|
|
"expo-splash-screen": "~31.0.13",
|
|
"expo-system-ui": "~6.0.9",
|
|
"expo-updates": "~29.0.17",
|
|
"expo-video": "~3.0.16",
|
|
"expo-video-thumbnails": "^10.0.8",
|
|
"expo-web-browser": "~15.0.10",
|
|
"fast-deep-equal": "^3.1.3",
|
|
"fast-text-encoding": "^1.0.6",
|
|
"fuse.js": "^7.1.0",
|
|
"hls.js": "^1.6.2",
|
|
"idb-keyval": "^6.2.2",
|
|
"js-sha256": "^0.9.0",
|
|
"jwt-decode": "^4.0.0",
|
|
"lande": "^1.0.10",
|
|
"libphonenumber-js": "^1.12.31",
|
|
"lodash.chunk": "^4.2.0",
|
|
"lodash.debounce": "^4.0.8",
|
|
"lodash.shuffle": "^4.2.0",
|
|
"lodash.throttle": "^4.1.1",
|
|
"mediabunny": "^1.25.3",
|
|
"multiformats": "^13.4.2",
|
|
"nanoid": "^5.0.5",
|
|
"normalize-url": "^8.0.0",
|
|
"psl": "1.9.0",
|
|
"radix-ui": "^1.4.3",
|
|
"react": "19.1.0",
|
|
"react-compiler-runtime": "19.1.0-rc.3",
|
|
"react-dom": "19.1.0",
|
|
"react-hotkeys-hook": "5.2.4",
|
|
"react-image-crop": "^11.0.7",
|
|
"react-is": "19",
|
|
"react-keyed-flatten-children": "^5.0.0",
|
|
"react-native": "0.81.5",
|
|
"react-native-compressor": "1.13.0",
|
|
"react-native-date-picker": "^5.0.13",
|
|
"react-native-device-attest": "^0.1.6",
|
|
"react-native-drawer-layout": "^4.2.3",
|
|
"react-native-edge-to-edge": "^1.8.1",
|
|
"react-native-gesture-handler": "~2.28.0",
|
|
"react-native-keyboard-controller": "^1.21.8",
|
|
"react-native-pager-view": "6.8.0",
|
|
"react-native-progress": "bluesky-social/react-native-progress",
|
|
"react-native-qrcode-styled": "^0.3.3",
|
|
"react-native-reanimated": "3.19.1",
|
|
"react-native-safe-area-context": "~5.6.0",
|
|
"react-native-screens": "4.24.0",
|
|
"react-native-svg": "15.12.1",
|
|
"react-native-uitextview": "^1.4.0",
|
|
"react-native-uuid": "^2.0.3",
|
|
"react-native-view-shot": "^4.0.3",
|
|
"react-native-web": "^0.21.0",
|
|
"react-native-web-webview": "^1.0.2",
|
|
"react-native-webview": "^13.15.0",
|
|
"react-remove-scroll-bar": "^2.3.8",
|
|
"react-responsive": "^10.0.1",
|
|
"react-textarea-autosize": "^8.5.3",
|
|
"setimmediate": "^1.0.5",
|
|
"slugify": "^1.6.9",
|
|
"sonner": "^2.0.7",
|
|
"sonner-native": "0.21.0",
|
|
"tippy.js": "^6.3.7",
|
|
"tlds": "^1.234.0",
|
|
"tldts": "^6.1.46",
|
|
"unicode-segmenter": "0.14.5",
|
|
"zod": "^3.25.76"
|
|
},
|
|
"devDependencies": {
|
|
"@babel/core": "^7.26.0",
|
|
"@babel/preset-env": "^7.26.0",
|
|
"@babel/runtime": "^7.26.0",
|
|
"@crowdin/cli": "^4.14.1",
|
|
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
|
"@lingui/cli": "^5.9.2",
|
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
|
"@react-native/babel-preset": "0.81.5",
|
|
"@react-native/typescript-config": "^0.81.5",
|
|
"@sentry/webpack-plugin": "^3.2.2",
|
|
"@testing-library/react-native": "^13.2.0",
|
|
"@types/jest": "29.5.14",
|
|
"@types/lodash.chunk": "^4.2.7",
|
|
"@types/lodash.debounce": "^4.0.7",
|
|
"@types/lodash.shuffle": "^4.2.7",
|
|
"@types/psl": "1.1.1",
|
|
"@types/react": "^19.1.17",
|
|
"@types/react-dom": "^19.1.11",
|
|
"@typescript/native-preview": "^7.0.0-dev.20260428.1",
|
|
"babel-jest": "^29.7.0",
|
|
"babel-plugin-module-resolver": "^5.0.2",
|
|
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
|
"babel-preset-expo": "~54.0.10",
|
|
"eslint-plugin-bsky-internal": "link:eslint",
|
|
"eslint-plugin-react-compiler": "19.1.0-rc.2",
|
|
"eslint-plugin-react-native": "^5.0.0",
|
|
"eslint-plugin-react-native-a11y": "^3.5.1",
|
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
|
"file-loader": "6.2.0",
|
|
"globals": "^17.0.0",
|
|
"husky": "^9.1.7",
|
|
"is-ci": "^3.0.1",
|
|
"jest": "^29.7.0",
|
|
"jest-expo": "~54.0.17",
|
|
"jest-junit": "^16.0.0",
|
|
"lint-staged": "^17.0.8",
|
|
"oxlint": "^1.73.0",
|
|
"oxlint-tsgolint": "^0.24.0",
|
|
"prettier": "^3.8.3",
|
|
"react-native-dotenv": "^3.4.11",
|
|
"react-refresh": "^0.14.0",
|
|
"svgo": "^4.0.2",
|
|
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
|
"typescript": "^6.0.2",
|
|
"webpack-bundle-analyzer": "^4.10.1"
|
|
},
|
|
"jest": {
|
|
"preset": "jest-expo/ios",
|
|
"setupFilesAfterEnv": [
|
|
"./jest/jestSetup.js"
|
|
],
|
|
"moduleFileExtensions": [
|
|
"ts",
|
|
"tsx",
|
|
"js",
|
|
"jsx",
|
|
"json",
|
|
"node"
|
|
],
|
|
"transform": {
|
|
"\\.[jt]sx?$": "babel-jest"
|
|
},
|
|
"moduleNameMapper": {
|
|
"^multiformats$": "<rootDir>/node_modules/multiformats/dist/src/index.js",
|
|
"^multiformats/cid$": "<rootDir>/node_modules/multiformats/dist/src/cid.js",
|
|
"^multiformats/bases/base32$": "<rootDir>/node_modules/multiformats/dist/src/bases/base32.js",
|
|
"^multiformats/hashes/digest$": "<rootDir>/node_modules/multiformats/dist/src/hashes/digest.js",
|
|
"^multiformats/hashes/sha2$": "<rootDir>/node_modules/multiformats/dist/src/hashes/sha2.js",
|
|
"^uint8arrays/from-string$": "<rootDir>/node_modules/uint8arrays/dist/src/from-string.js",
|
|
"^uint8arrays/to-string$": "<rootDir>/node_modules/uint8arrays/dist/src/to-string.js",
|
|
"^unicode-segmenter/grapheme$": "<rootDir>/node_modules/unicode-segmenter/grapheme.cjs",
|
|
"^await-lock$": "<rootDir>/node_modules/await-lock/build/AwaitLock.js"
|
|
},
|
|
"transformIgnorePatterns": [
|
|
"node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|nanoid|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|normalize-url|react-native-svg|@sentry/.*|sentry-expo|bcp-47-match|@atproto/.*|multiformats|uint8arrays|@ipld/.*|cborg|await-lock)"
|
|
],
|
|
"modulePathIgnorePatterns": [
|
|
"__tests__/.*/__mocks__",
|
|
"__e2e__/.*",
|
|
"bskylink/.*"
|
|
],
|
|
"coveragePathIgnorePatterns": [
|
|
"<rootDir>/node_modules/",
|
|
"<rootDir>/src/platform",
|
|
"<rootDir>/src/third-party",
|
|
"<rootDir>/src/view/com/util",
|
|
"<rootDir>/src/state/lib",
|
|
"<rootDir>/__tests__/test-utils.js"
|
|
],
|
|
"reporters": [
|
|
"default",
|
|
"jest-junit"
|
|
]
|
|
},
|
|
"browserslist": {
|
|
"production": [
|
|
">0.2%",
|
|
"not dead",
|
|
"not op_mini all"
|
|
],
|
|
"development": [
|
|
"last 1 chrome version",
|
|
"last 1 firefox version",
|
|
"last 1 safari version"
|
|
]
|
|
},
|
|
"lint-staged": {
|
|
"*{.js,.jsx,.ts,.tsx}": [
|
|
"oxlint --fix"
|
|
],
|
|
"*{.js,.jsx,.ts,.tsx,.css}": [
|
|
"prettier --cache --write --ignore-unknown"
|
|
],
|
|
"assets/icons/*.svg": [
|
|
"svgo"
|
|
]
|
|
}
|
|
}
|