@oxy.so/services 12.14.0 → 13.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/ui/components/ExpoImage.js +13 -0
- package/lib/commonjs/ui/components/ExpoImage.js.map +1 -0
- package/lib/commonjs/ui/components/ExpoImage.macos.js +80 -0
- package/lib/commonjs/ui/components/ExpoImage.macos.js.map +1 -0
- package/lib/commonjs/ui/components/KeyboardBoundary.macos.js +19 -0
- package/lib/commonjs/ui/components/KeyboardBoundary.macos.js.map +1 -0
- package/lib/commonjs/ui/components/OxyConsentScreen.js +10 -7
- package/lib/commonjs/ui/components/OxyConsentScreen.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/FileViewer.js +3 -3
- package/lib/commonjs/ui/components/fileManagement/FileViewer.js.map +1 -1
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js +2 -2
- package/lib/commonjs/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/commonjs/ui/oauth/explicitOAuthConsent.js +10 -5
- package/lib/commonjs/ui/oauth/explicitOAuthConsent.js.map +1 -1
- package/lib/commonjs/ui/oauth/nativeAuthTransport.js +1 -1
- package/lib/commonjs/ui/oauth/nativeAuthTransport.js.map +1 -1
- package/lib/commonjs/ui/screens/AvatarCropScreen.js +2 -2
- package/lib/commonjs/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js +2 -2
- package/lib/commonjs/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/FileManagementScreen.js +4 -4
- package/lib/commonjs/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/OxyOneScreen.js +2 -2
- package/lib/commonjs/ui/screens/OxyOneScreen.js.map +1 -1
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js +2 -2
- package/lib/commonjs/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/commonjs/ui/utils/imageSize.macos.js +23 -0
- package/lib/commonjs/ui/utils/imageSize.macos.js.map +1 -0
- package/lib/module/ui/components/ExpoImage.js +14 -0
- package/lib/module/ui/components/ExpoImage.js.map +1 -0
- package/lib/module/ui/components/ExpoImage.macos.js +76 -0
- package/lib/module/ui/components/ExpoImage.macos.js.map +1 -0
- package/lib/module/ui/components/KeyboardBoundary.macos.js +14 -0
- package/lib/module/ui/components/KeyboardBoundary.macos.js.map +1 -0
- package/lib/module/ui/components/OxyConsentScreen.js +10 -7
- package/lib/module/ui/components/OxyConsentScreen.js.map +1 -1
- package/lib/module/ui/components/fileManagement/FileViewer.js +1 -1
- package/lib/module/ui/components/fileManagement/FileViewer.js.map +1 -1
- package/lib/module/ui/components/fileManagement/UploadPreview.js +1 -1
- package/lib/module/ui/components/fileManagement/UploadPreview.js.map +1 -1
- package/lib/module/ui/oauth/explicitOAuthConsent.js +10 -5
- package/lib/module/ui/oauth/explicitOAuthConsent.js.map +1 -1
- package/lib/module/ui/oauth/nativeAuthTransport.js +1 -1
- package/lib/module/ui/oauth/nativeAuthTransport.js.map +1 -1
- package/lib/module/ui/screens/AvatarCropScreen.js +1 -1
- package/lib/module/ui/screens/AvatarCropScreen.js.map +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js +1 -1
- package/lib/module/ui/screens/EditProfileFieldScreen.js.map +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js +1 -1
- package/lib/module/ui/screens/FileManagementScreen.js.map +1 -1
- package/lib/module/ui/screens/OxyOneScreen.js +1 -1
- package/lib/module/ui/screens/OxyOneScreen.js.map +1 -1
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js +1 -1
- package/lib/module/ui/screens/fileManagement/PhotoPickerSection.js.map +1 -1
- package/lib/module/ui/utils/imageSize.macos.js +18 -0
- package/lib/module/ui/utils/imageSize.macos.js.map +1 -0
- package/lib/typescript/commonjs/ui/components/ExpoImage.d.ts +12 -0
- package/lib/typescript/commonjs/ui/components/ExpoImage.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/ExpoImage.macos.d.ts +16 -0
- package/lib/typescript/commonjs/ui/components/ExpoImage.macos.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/KeyboardBoundary.macos.d.ts +10 -0
- package/lib/typescript/commonjs/ui/components/KeyboardBoundary.macos.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts +3 -1
- package/lib/typescript/commonjs/ui/components/OxyConsentScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts +2 -1
- package/lib/typescript/commonjs/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts +28 -50
- package/lib/typescript/commonjs/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/usePersonalPlans.d.ts +13 -13
- package/lib/typescript/commonjs/ui/hooks/queries/usePersonalPlans.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/hooks/queries/useSupervision.d.ts +108 -108
- package/lib/typescript/commonjs/ui/icons/Ionicons.d.ts +1 -1
- package/lib/typescript/commonjs/ui/icons/MaterialCommunityIcons.d.ts +1 -1
- package/lib/typescript/commonjs/ui/oauth/explicitOAuthConsent.d.ts +4 -6
- package/lib/typescript/commonjs/ui/oauth/explicitOAuthConsent.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/oauth/nativeAuthTransport.d.ts.map +1 -1
- package/lib/typescript/commonjs/ui/utils/imageSize.macos.d.ts +6 -0
- package/lib/typescript/commonjs/ui/utils/imageSize.macos.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ExpoImage.d.ts +12 -0
- package/lib/typescript/module/ui/components/ExpoImage.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/ExpoImage.macos.d.ts +16 -0
- package/lib/typescript/module/ui/components/ExpoImage.macos.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/KeyboardBoundary.macos.d.ts +10 -0
- package/lib/typescript/module/ui/components/KeyboardBoundary.macos.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts +3 -1
- package/lib/typescript/module/ui/components/OxyConsentScreen.d.ts.map +1 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts +2 -1
- package/lib/typescript/module/ui/context/oxyContextTypes.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts +28 -50
- package/lib/typescript/module/ui/hooks/mutations/useAccountMutations.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/usePersonalPlans.d.ts +13 -13
- package/lib/typescript/module/ui/hooks/queries/usePersonalPlans.d.ts.map +1 -1
- package/lib/typescript/module/ui/hooks/queries/useSupervision.d.ts +108 -108
- package/lib/typescript/module/ui/icons/Ionicons.d.ts +1 -1
- package/lib/typescript/module/ui/icons/MaterialCommunityIcons.d.ts +1 -1
- package/lib/typescript/module/ui/oauth/explicitOAuthConsent.d.ts +4 -6
- package/lib/typescript/module/ui/oauth/explicitOAuthConsent.d.ts.map +1 -1
- package/lib/typescript/module/ui/oauth/nativeAuthTransport.d.ts.map +1 -1
- package/lib/typescript/module/ui/utils/imageSize.macos.d.ts +6 -0
- package/lib/typescript/module/ui/utils/imageSize.macos.d.ts.map +1 -0
- package/package.json +35 -34
- package/src/ui/components/ExpoImage.macos.tsx +59 -0
- package/src/ui/components/ExpoImage.tsx +11 -0
- package/src/ui/components/KeyboardBoundary.macos.tsx +8 -0
- package/src/ui/components/OxyConsentScreen.tsx +40 -31
- package/src/ui/components/__tests__/OxyConsentScreen.test.tsx +13 -0
- package/src/ui/components/fileManagement/FileViewer.tsx +1 -1
- package/src/ui/components/fileManagement/UploadPreview.tsx +1 -1
- package/src/ui/context/oxyContextTypes.ts +2 -1
- package/src/ui/oauth/__tests__/explicitOAuthConsent.test.ts +17 -0
- package/src/ui/oauth/explicitOAuthConsent.ts +10 -5
- package/src/ui/oauth/nativeAuthTransport.ts +5 -1
- package/src/ui/screens/AvatarCropScreen.tsx +1 -1
- package/src/ui/screens/EditProfileFieldScreen.tsx +1 -1
- package/src/ui/screens/FileManagementScreen.tsx +1 -1
- package/src/ui/screens/OxyOneScreen.tsx +1 -1
- package/src/ui/screens/fileManagement/PhotoPickerSection.tsx +1 -1
- package/src/ui/utils/imageSize.macos.ts +18 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxy.so/services",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.1.0",
|
|
4
4
|
"description": "OxyHQ Expo/React Native SDK — UI components, screens, and native features",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
@@ -140,6 +140,7 @@
|
|
|
140
140
|
"verify:package": "node scripts/verify-package.mjs",
|
|
141
141
|
"generate:icon-fonts": "node scripts/generate-icon-font-subsets.mjs",
|
|
142
142
|
"check:icon-fonts": "node scripts/check-icon-font-subsets.mjs",
|
|
143
|
+
"check:compat-expo-54": "bun compat/expo-54/check.mjs",
|
|
143
144
|
"build:js": "bun x react-native-builder-bob build --target commonjs && bun x react-native-builder-bob build --target module && bun run copy-assets",
|
|
144
145
|
"test": "jest --passWithNoTests",
|
|
145
146
|
"test:watch": "jest --watch",
|
|
@@ -150,7 +151,7 @@
|
|
|
150
151
|
"delete-dts.js": "find ./lib/commonjs -name '*.d.js*' -delete && find ./lib/module -name '*.d.js*' -delete"
|
|
151
152
|
},
|
|
152
153
|
"dependencies": {
|
|
153
|
-
"@oxy.so/contracts": "^
|
|
154
|
+
"@oxy.so/contracts": "^6.0.0",
|
|
154
155
|
"color": "^5.0.3",
|
|
155
156
|
"@peable.to/sdk": "0.4.1"
|
|
156
157
|
},
|
|
@@ -159,11 +160,10 @@
|
|
|
159
160
|
"@commitlint/config-conventional": "^21.2.0",
|
|
160
161
|
"@expo/app-integrity": "~58.0.2",
|
|
161
162
|
"@expo/vector-icons": "^15.0.3",
|
|
162
|
-
"@oxy.so/core": "
|
|
163
|
+
"@oxy.so/core": "7.1.0",
|
|
163
164
|
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
164
165
|
"@react-native-community/netinfo": "^12.0.1",
|
|
165
166
|
"@react-native/babel-preset": "^0.88.0",
|
|
166
|
-
"@release-it/conventional-changelog": "^12.0.2",
|
|
167
167
|
"@tanstack/query-async-storage-persister": "^5.101",
|
|
168
168
|
"@tanstack/query-sync-storage-persister": "^5.101",
|
|
169
169
|
"@tanstack/react-query": "^5.101",
|
|
@@ -176,26 +176,26 @@
|
|
|
176
176
|
"@types/react": "*",
|
|
177
177
|
"@oxy.so/bloom": "15.18.0",
|
|
178
178
|
"copyfiles": "^2.4.1",
|
|
179
|
-
"expo-clipboard": "~58.0.
|
|
180
|
-
"expo-constants": "~58.0.
|
|
181
|
-
"expo-file-system": "~58.0.
|
|
179
|
+
"expo-clipboard": "~58.0.4",
|
|
180
|
+
"expo-constants": "~58.0.13",
|
|
181
|
+
"expo-file-system": "~58.0.11",
|
|
182
182
|
"expo-haptics": "~58.0.7",
|
|
183
|
-
"expo-image": "~58.0.
|
|
184
|
-
"expo-image-manipulator": "~58.0.
|
|
183
|
+
"expo-image": "~58.0.17",
|
|
184
|
+
"expo-image-manipulator": "~58.0.15",
|
|
185
185
|
"expo-linear-gradient": "~58.0.3",
|
|
186
|
-
"expo-notifications": "~58.1.
|
|
187
|
-
"expo-modules-core": "~58.0.
|
|
186
|
+
"expo-notifications": "~58.1.6",
|
|
187
|
+
"expo-modules-core": "~58.0.26",
|
|
188
188
|
"expo-secure-store": "~58.0.2",
|
|
189
189
|
"expo-web-browser": "~58.0.6",
|
|
190
190
|
"husky": "^4.3.8",
|
|
191
191
|
"jest": "^30.5.1",
|
|
192
192
|
"lint-staged": "^15.2.4",
|
|
193
|
-
"nativewind": "5.0.0-
|
|
193
|
+
"nativewind": "5.0.0-rc.0",
|
|
194
194
|
"react": "19.3.0",
|
|
195
195
|
"react-dom": "19.3.0",
|
|
196
196
|
"react-native": "0.88.0",
|
|
197
197
|
"react-native-builder-bob": "^0.43.0",
|
|
198
|
-
"react-native-css": "
|
|
198
|
+
"react-native-css": "3.1.0-rc.0",
|
|
199
199
|
"react-native-gesture-handler": "~3.3.0",
|
|
200
200
|
"react-native-keyboard-controller": "1.22.7",
|
|
201
201
|
"react-native-qrcode-svg": "^6.3.0",
|
|
@@ -206,15 +206,16 @@
|
|
|
206
206
|
"ts-jest": "^29.4.12",
|
|
207
207
|
"typescript": "^5.9.2",
|
|
208
208
|
"zustand": "^5.0.14",
|
|
209
|
-
"expo-video": "~58.0.
|
|
209
|
+
"expo-video": "~58.0.12"
|
|
210
210
|
},
|
|
211
211
|
"//@oxy.so/bloom": "Bloom 11.1.0 adds the shared grouped sections, usage card, subscription plans, frame appearance and overlay navigation APIs used by this SDK. First-party Bloom peers remain open above this tested minimum.",
|
|
212
212
|
"//@oxy.so/core": "Core 6.16.0 supplies `requireServerVerdict` and `onHolderRejected`, with which the cold boot checks a session it painted from the cache; 6.13.0 supplies the `accounts.settings.*` strings (picture, categories) the account settings speak in every language; 6.12.0 supplies `fileManagement.contentLost` and the `lost` file status a lost file is listed with; 6.11.0 supplies the `follow.errors.*` strings the follow error codes are worded with; 6.4.0 the `follow.*` strings the follow buttons read for every verb and language; 6.1.0 the `oxy.auth.email.{startChange,change,remove}` and `oxy.auth.password.remove` the sign-in & security panels call. Keep one Core instance per app; raise this floor with the root catalogue when new runtime APIs are required.",
|
|
213
|
+
"//react-native": "React Native 0.81 to 0.88, React 19.1+ and Expo SDK 54 to 58. The floors are the Expo SDK 54 stack (react-native 0.81.6, react 19.1.4, react-native-web 0.21.4, expo 54.0.38 and the module versions its bundledNativeModules.json pins), which compat/expo-54 installs as an external consumer and checks on every CI run (`bun check.mjs`): every peer here admits that stack, services' published src typechecks against its types, and <OxyProvider> mounts and settles its cold boot on iOS (React Native 0.81), web (react-native-web 0.21) and react-native-macos 0.81 with the native modules macOS lacks absent. Astro, Oxy's browser, runs react-native-macos 0.81 (0.83 is its latest release), which is why the floor is not 0.85. The SDK 56 floors these replaced were the versions current when the ranges were first written, not measurements.",
|
|
213
214
|
"peerDependencies": {
|
|
214
|
-
"@expo/app-integrity": ">=
|
|
215
|
+
"@expo/app-integrity": ">=0.1.10 <59.0.0",
|
|
215
216
|
"@expo/vector-icons": "^15.0.3",
|
|
216
217
|
"@oxy.so/bloom": ">=11.1.0",
|
|
217
|
-
"@oxy.so/core": "^
|
|
218
|
+
"@oxy.so/core": "^7.0.0",
|
|
218
219
|
"@react-native-async-storage/async-storage": "^2.0.0",
|
|
219
220
|
"@react-native-community/netinfo": ">=11.4.1 <13.0.0",
|
|
220
221
|
"@tanstack/query-async-storage-persister": "^5.101",
|
|
@@ -223,31 +224,31 @@
|
|
|
223
224
|
"@tanstack/react-query-persist-client": "^5.101",
|
|
224
225
|
"@types/react": "<20.0.0",
|
|
225
226
|
"@types/react-native": "<1.0.0",
|
|
226
|
-
"expo": ">=
|
|
227
|
-
"expo-clipboard": ">=
|
|
228
|
-
"expo-constants": ">=
|
|
229
|
-
"expo-document-picker": ">=
|
|
230
|
-
"expo-file-system": ">=
|
|
231
|
-
"expo-haptics": ">=
|
|
227
|
+
"expo": ">=54.0.0 <59.0.0",
|
|
228
|
+
"expo-clipboard": ">=8.0.0 <59.0.0",
|
|
229
|
+
"expo-constants": ">=18.0.0 <59.0.0",
|
|
230
|
+
"expo-document-picker": ">=14.0.0 <59.0.0",
|
|
231
|
+
"expo-file-system": ">=19.0.0 <59.0.0",
|
|
232
|
+
"expo-haptics": ">=15.0.0 <59.0.0",
|
|
232
233
|
"expo-image": ">=2.0.0 <59.0.0",
|
|
233
|
-
"expo-image-manipulator": ">=
|
|
234
|
-
"expo-image-picker": ">=
|
|
235
|
-
"expo-linear-gradient": ">=
|
|
234
|
+
"expo-image-manipulator": ">=14.0.0 <59.0.0",
|
|
235
|
+
"expo-image-picker": ">=17.0.0 <59.0.0",
|
|
236
|
+
"expo-linear-gradient": ">=15.0.0 <59.0.0",
|
|
236
237
|
"expo-modules-core": "<59.0.0",
|
|
237
|
-
"expo-notifications": ">=
|
|
238
|
-
"expo-web-browser": ">=
|
|
238
|
+
"expo-notifications": ">=0.32.0 <59.0.0",
|
|
239
|
+
"expo-web-browser": ">=15.0.0 <59.0.0",
|
|
239
240
|
"nativewind": ">=5.0.0-preview.3 <6.0.0",
|
|
240
241
|
"react-native-css": "^3.0.6 || 3.1.0-rc.0",
|
|
241
242
|
"react": ">=18.0.0 <20.0.0",
|
|
242
|
-
"react-native": ">=0.
|
|
243
|
-
"react-native-gesture-handler": ">=2.
|
|
244
|
-
"react-native-keyboard-controller": ">=1.
|
|
243
|
+
"react-native": ">=0.81.0 <0.89.0",
|
|
244
|
+
"react-native-gesture-handler": ">=2.28.0 <4.0.0",
|
|
245
|
+
"react-native-keyboard-controller": ">=1.18.5 <2.0.0",
|
|
245
246
|
"react-native-qrcode-svg": "^6.3.0",
|
|
246
|
-
"react-native-reanimated": ">=4.
|
|
247
|
-
"react-native-safe-area-context": ">=5.
|
|
248
|
-
"react-native-svg": ">=15.
|
|
247
|
+
"react-native-reanimated": ">=4.1.0 <5.0.0",
|
|
248
|
+
"react-native-safe-area-context": ">=5.6.0 <6.0.0",
|
|
249
|
+
"react-native-svg": ">=15.12.1 <16.0.0",
|
|
249
250
|
"zustand": "^5.0.0",
|
|
250
|
-
"expo-video": ">=
|
|
251
|
+
"expo-video": ">=3.0.0 <59.0.0"
|
|
251
252
|
},
|
|
252
253
|
"peerDependenciesMeta": {
|
|
253
254
|
"nativewind": {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-native-macos fork of `ExpoImage.tsx`. expo-image ships no macOS
|
|
3
|
+
* podspec, and importing it throws there (`requireNativeModule('ExpoImage')`
|
|
4
|
+
* runs at import), so on macOS the SDK draws with react-native's `Image`,
|
|
5
|
+
* which react-native-macos backs with NSImage. Fresco, the reason the other
|
|
6
|
+
* platforms avoid react-native's `Image`, is Android-only.
|
|
7
|
+
*
|
|
8
|
+
* It accepts expo-image's props, so every call site typechecks once against the
|
|
9
|
+
* default fork, and maps the ones the SDK uses; the rest (transition, cache
|
|
10
|
+
* policy, placeholders) have no macOS equivalent here and are dropped.
|
|
11
|
+
*/
|
|
12
|
+
import type { ImageContentFit, ImageProps, ImageSource } from 'expo-image';
|
|
13
|
+
import { Image, type ImageResizeMode, type ImageSourcePropType } from 'react-native';
|
|
14
|
+
|
|
15
|
+
const RESIZE_MODE: Record<ImageContentFit, ImageResizeMode> = {
|
|
16
|
+
cover: 'cover',
|
|
17
|
+
contain: 'contain',
|
|
18
|
+
fill: 'stretch',
|
|
19
|
+
none: 'center',
|
|
20
|
+
'scale-down': 'contain',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function toImageSource(source: ImageProps['source']): ImageSourcePropType | undefined {
|
|
24
|
+
if (source == null) return undefined;
|
|
25
|
+
if (typeof source === 'number') return source;
|
|
26
|
+
if (typeof source === 'string') return { uri: source };
|
|
27
|
+
if (Array.isArray(source)) return source.length > 0 ? toImageSource(source[0]) : undefined;
|
|
28
|
+
if (typeof source === 'object' && 'uri' in source) {
|
|
29
|
+
const { uri, headers, width, height } = source as ImageSource;
|
|
30
|
+
return { uri, headers, width: width ?? undefined, height: height ?? undefined };
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function ExpoImage({
|
|
36
|
+
source,
|
|
37
|
+
contentFit = 'cover',
|
|
38
|
+
onError,
|
|
39
|
+
style,
|
|
40
|
+
blurRadius,
|
|
41
|
+
accessible,
|
|
42
|
+
accessibilityLabel,
|
|
43
|
+
testID,
|
|
44
|
+
className,
|
|
45
|
+
}: ImageProps & { className?: string }) {
|
|
46
|
+
return (
|
|
47
|
+
<Image
|
|
48
|
+
source={toImageSource(source) ?? { uri: '' }}
|
|
49
|
+
resizeMode={RESIZE_MODE[contentFit]}
|
|
50
|
+
onError={onError ? () => onError({ error: 'The image could not be loaded' }) : undefined}
|
|
51
|
+
style={style}
|
|
52
|
+
blurRadius={blurRadius}
|
|
53
|
+
accessible={accessible}
|
|
54
|
+
accessibilityLabel={accessibilityLabel}
|
|
55
|
+
testID={testID}
|
|
56
|
+
{...(className ? { className } : null)}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The image every SDK surface draws with: expo-image's `Image` (Glide on
|
|
3
|
+
* Android, SDWebImage on iOS, an `<img>` on web), never react-native's
|
|
4
|
+
* (`__tests__/packaging/rnImageBoundary.test.ts`).
|
|
5
|
+
*
|
|
6
|
+
* Its one fork, `ExpoImage.macos.tsx`, exists because expo-image has no macOS
|
|
7
|
+
* implementation: its module calls `requireNativeModule('ExpoImage')` when it
|
|
8
|
+
* is first imported, so on react-native-macos merely importing this file's
|
|
9
|
+
* target would throw and take the whole SDK down with it.
|
|
10
|
+
*/
|
|
11
|
+
export { Image as ExpoImage } from 'expo-image';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { FC, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* react-native-macos fork: react-native-keyboard-controller has no macOS
|
|
5
|
+
* implementation and throws when imported without its native module, and a
|
|
6
|
+
* desktop keyboard never covers the window, so there is nothing to track.
|
|
7
|
+
*/
|
|
8
|
+
export const KeyboardBoundary: FC<{ children: ReactNode }> = ({ children }) => <>{children}</>;
|
|
@@ -73,6 +73,8 @@ export interface OxyConsentResource {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
export interface OxyConsentScreenProps {
|
|
76
|
+
/** Presentation only: own sign-in has no permission grant. External MCP stays consent. */
|
|
77
|
+
mode?: 'consent' | 'sign-in';
|
|
76
78
|
/** The resolved requesting application. */
|
|
77
79
|
application: OxyConsentApplication;
|
|
78
80
|
/** OAuth scopes requested by the client (mapped to friendly labels). */
|
|
@@ -215,6 +217,7 @@ function ConsentLink({
|
|
|
215
217
|
|
|
216
218
|
export function OxyConsentScreen({
|
|
217
219
|
application,
|
|
220
|
+
mode = 'consent',
|
|
218
221
|
scopes,
|
|
219
222
|
user,
|
|
220
223
|
resource,
|
|
@@ -269,10 +272,12 @@ export function OxyConsentScreen({
|
|
|
269
272
|
</View>
|
|
270
273
|
</View>
|
|
271
274
|
<Text style={[styles.title, { color: theme.colors.text }]}>
|
|
272
|
-
{t('consent.title', { app: appName })}
|
|
275
|
+
{mode === 'sign-in' ? t('signin.title') : t('consent.title', { app: appName })}
|
|
273
276
|
</Text>
|
|
274
277
|
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>
|
|
275
|
-
{
|
|
278
|
+
{mode === 'sign-in'
|
|
279
|
+
? t('signin.chooser.subtitleToApp', { app: appName })
|
|
280
|
+
: t('consent.subtitle', { app: appName })}
|
|
276
281
|
</Text>
|
|
277
282
|
</View>
|
|
278
283
|
|
|
@@ -333,36 +338,38 @@ export function OxyConsentScreen({
|
|
|
333
338
|
</View>
|
|
334
339
|
) : null}
|
|
335
340
|
|
|
336
|
-
{/*
|
|
337
|
-
|
|
338
|
-
<
|
|
339
|
-
{
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
permissionRows.
|
|
349
|
-
|
|
341
|
+
{/* Own sign-in has no permissions section, including the basic fallback. */}
|
|
342
|
+
{mode === 'consent' ? (
|
|
343
|
+
<View style={styles.section}>
|
|
344
|
+
<Text style={[styles.sectionLabel, { color: theme.colors.textSecondary }]}>
|
|
345
|
+
{t('consent.permissions.title')}
|
|
346
|
+
</Text>
|
|
347
|
+
<View
|
|
348
|
+
style={[
|
|
349
|
+
styles.card,
|
|
350
|
+
{ borderColor: theme.colors.border, backgroundColor: theme.colors.card },
|
|
351
|
+
]}
|
|
352
|
+
>
|
|
353
|
+
{permissionRows.length > 0 ? (
|
|
354
|
+
permissionRows.map((row) => (
|
|
355
|
+
<View key={row.scope} testID={`consent-scope-${row.scope}`} style={styles.row}>
|
|
356
|
+
<View style={[styles.bullet, { backgroundColor: theme.colors.primary }]} />
|
|
357
|
+
<Text style={[styles.rowText, { color: theme.colors.text }]}>
|
|
358
|
+
{permissionRowLabel(row, t)}
|
|
359
|
+
</Text>
|
|
360
|
+
</View>
|
|
361
|
+
))
|
|
362
|
+
) : (
|
|
363
|
+
<View testID="consent-scope-basic" style={styles.row}>
|
|
350
364
|
<View style={[styles.bullet, { backgroundColor: theme.colors.primary }]} />
|
|
351
365
|
<Text style={[styles.rowText, { color: theme.colors.text }]}>
|
|
352
|
-
{
|
|
366
|
+
{t('consent.permissions.basic')}
|
|
353
367
|
</Text>
|
|
354
368
|
</View>
|
|
355
|
-
)
|
|
356
|
-
|
|
357
|
-
<View testID="consent-scope-basic" style={styles.row}>
|
|
358
|
-
<View style={[styles.bullet, { backgroundColor: theme.colors.primary }]} />
|
|
359
|
-
<Text style={[styles.rowText, { color: theme.colors.text }]}>
|
|
360
|
-
{t('consent.permissions.basic')}
|
|
361
|
-
</Text>
|
|
362
|
-
</View>
|
|
363
|
-
)}
|
|
369
|
+
)}
|
|
370
|
+
</View>
|
|
364
371
|
</View>
|
|
365
|
-
|
|
372
|
+
) : null}
|
|
366
373
|
|
|
367
374
|
{resource && resource.writeActions.length > 0 ? (
|
|
368
375
|
<View style={styles.section}>
|
|
@@ -479,7 +486,7 @@ export function OxyConsentScreen({
|
|
|
479
486
|
loading={busy}
|
|
480
487
|
style={styles.actionButton}
|
|
481
488
|
>
|
|
482
|
-
{t('consent.allow', { app: appName })}
|
|
489
|
+
{mode === 'sign-in' ? t('signin.actions.continue') : t('consent.allow', { app: appName })}
|
|
483
490
|
</Button>
|
|
484
491
|
<Button
|
|
485
492
|
testID="consent-deny"
|
|
@@ -493,9 +500,11 @@ export function OxyConsentScreen({
|
|
|
493
500
|
</Button>
|
|
494
501
|
</View>
|
|
495
502
|
|
|
496
|
-
|
|
497
|
-
{
|
|
498
|
-
|
|
503
|
+
{mode === 'consent' ? (
|
|
504
|
+
<Text style={[styles.disclaimer, { color: theme.colors.textSecondary }]}>
|
|
505
|
+
{t('consent.disclaimer', { app: appName })}
|
|
506
|
+
</Text>
|
|
507
|
+
) : null}
|
|
499
508
|
</ScrollView>
|
|
500
509
|
);
|
|
501
510
|
}
|
|
@@ -25,6 +25,7 @@ function renderScreen(props: Partial<OxyConsentScreenProps> = {}) {
|
|
|
25
25
|
scopes={props.scopes ?? ['openid', 'profile']}
|
|
26
26
|
user={props.user}
|
|
27
27
|
resource={props.resource}
|
|
28
|
+
mode={props.mode}
|
|
28
29
|
onAllow={props.onAllow ?? onAllow}
|
|
29
30
|
onDeny={props.onDeny ?? onDeny}
|
|
30
31
|
busy={props.busy}
|
|
@@ -36,6 +37,18 @@ function renderScreen(props: Partial<OxyConsentScreenProps> = {}) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
describe('OxyConsentScreen', () => {
|
|
40
|
+
it('renders own sign-in without any permission grant language or rows', () => {
|
|
41
|
+
const { queryByTestId, queryByText, getByTestId } = renderScreen({
|
|
42
|
+
mode: 'sign-in',
|
|
43
|
+
scopes: ['files:write'],
|
|
44
|
+
application: { name: 'Inbox', isOfficial: true },
|
|
45
|
+
});
|
|
46
|
+
expect(queryByTestId('consent-scope-files:write')).toBeNull();
|
|
47
|
+
expect(queryByTestId('consent-scope-basic')).toBeNull();
|
|
48
|
+
expect(queryByText('Permissions requested')).toBeNull();
|
|
49
|
+
expect(getByTestId('consent-allow').textContent).toContain('Continue');
|
|
50
|
+
});
|
|
51
|
+
|
|
39
52
|
it('renders every requested scope with a friendly label and falls back to the raw scope for unknown ones', () => {
|
|
40
53
|
const { getByTestId } = renderScreen({ scopes: ['openid', 'files:write', 'custom:thing'] });
|
|
41
54
|
|
|
@@ -4,7 +4,7 @@ import { useMemo, useState, useEffect } from 'react';
|
|
|
4
4
|
import { View, ScrollView, StyleSheet } from 'react-native';
|
|
5
5
|
import { Button } from '@oxy.so/bloom/button';
|
|
6
6
|
import { Text } from '@oxy.so/bloom/typography';
|
|
7
|
-
import {
|
|
7
|
+
import { ExpoImage } from '../ExpoImage';
|
|
8
8
|
import MaterialCommunityIcons from '../../icons/MaterialCommunityIcons';
|
|
9
9
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
10
10
|
import type { FileMetadata } from '@oxy.so/core';
|
|
@@ -3,7 +3,7 @@ import { View, ScrollView, StyleSheet } from 'react-native';
|
|
|
3
3
|
import { Button } from '@oxy.so/bloom/button';
|
|
4
4
|
import { Card } from '@oxy.so/bloom/card';
|
|
5
5
|
import { Text } from '@oxy.so/bloom/typography';
|
|
6
|
-
import {
|
|
6
|
+
import { ExpoImage } from '../ExpoImage';
|
|
7
7
|
import Ionicons from '../../icons/Ionicons';
|
|
8
8
|
import { Dialog, type DialogControlProps } from '@oxy.so/bloom/dialog';
|
|
9
9
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
@@ -129,7 +129,8 @@ export interface OxyContextState {
|
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
131
|
* Ask the already-authenticated user for explicit OAuth consent to exact
|
|
132
|
-
* application scopes.
|
|
132
|
+
* external application scopes. Own Oxy apps do not use this operation.
|
|
133
|
+
* Must be called from a user gesture. Works on web and
|
|
133
134
|
* native and commits only a callback bound to the same user, state, PKCE pair
|
|
134
135
|
* and byte-exact redirect URI.
|
|
135
136
|
*/
|
|
@@ -82,6 +82,23 @@ describe('requestOAuthConsent', () => {
|
|
|
82
82
|
jest.restoreAllMocks();
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
it.each(['first_party', 'internal', 'system'])(
|
|
86
|
+
'does not request consent for an own %s application',
|
|
87
|
+
async (type) => {
|
|
88
|
+
const context = makeContext('native');
|
|
89
|
+
const apps = context.oxyServices.apps.getPublic as jest.Mock;
|
|
90
|
+
apps.mockResolvedValue({ id: 'own-app', type, scopes: [...EXACT_SCOPES] });
|
|
91
|
+
expect(
|
|
92
|
+
await requestOAuthConsent(context, {
|
|
93
|
+
redirectUri: NATIVE_REDIRECT_URI,
|
|
94
|
+
scopes: EXACT_SCOPES,
|
|
95
|
+
}),
|
|
96
|
+
).toEqual({ status: 'unsupported', reason: 'first-party-application' });
|
|
97
|
+
expect(openNative).not.toHaveBeenCalled();
|
|
98
|
+
expect(context.commitSession).not.toHaveBeenCalled();
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
85
102
|
it('uses the existing web popup transport with exact scopes and redirect', async () => {
|
|
86
103
|
const popup = fakePopup();
|
|
87
104
|
jest.spyOn(window, 'open').mockReturnValue(popup as unknown as Window);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Explicit OAuth consent for an already-authenticated Oxy user.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* caller must invoke this operation from a real user gesture; it never runs on
|
|
8
|
-
* mount, retries silently, or grants anything locally.
|
|
4
|
+
* External applications may request additional scopes through OAuth. Own Oxy
|
|
5
|
+
* applications use the account dialog and never create OAuth consent grants.
|
|
6
|
+
* The caller invokes this operation from a user gesture.
|
|
9
7
|
*/
|
|
10
8
|
|
|
11
9
|
import type { OxyServices, PublicApplication } from "@oxy.so/core";
|
|
@@ -44,6 +42,7 @@ export type OAuthConsentFailureReason =
|
|
|
44
42
|
|
|
45
43
|
export type OAuthConsentUnsupportedReason =
|
|
46
44
|
| "missing-client-id"
|
|
45
|
+
| "first-party-application"
|
|
47
46
|
| "identity-bound"
|
|
48
47
|
| "not-authenticated"
|
|
49
48
|
| "unsupported-platform";
|
|
@@ -173,6 +172,12 @@ export async function requestOAuthConsent(
|
|
|
173
172
|
return { status: "failed", reason: "client-resolution-failed" };
|
|
174
173
|
}
|
|
175
174
|
|
|
175
|
+
if (application.isOfficial || application.isInternal ||
|
|
176
|
+
["first_party", "internal", "system"].includes(application.type)) {
|
|
177
|
+
closeOAuthPopup(popup);
|
|
178
|
+
return { status: "unsupported", reason: "first-party-application" };
|
|
179
|
+
}
|
|
180
|
+
|
|
176
181
|
const configuredScopes = new Set(application.scopes);
|
|
177
182
|
if (options.scopes.some((scope) => !configuredScopes.has(scope))) {
|
|
178
183
|
closeOAuthPopup(popup);
|
|
@@ -87,7 +87,11 @@ export async function startNativeOAuthSignIn(
|
|
|
87
87
|
if (!redirectUrl.startsWith(prefix) || redirectUrl.includes('#'))
|
|
88
88
|
return { status: 'failed', reason: 'native-callback-invalid' };
|
|
89
89
|
const parameters = new URLSearchParams(redirectUrl.slice(prefix.length));
|
|
90
|
-
if (
|
|
90
|
+
if (
|
|
91
|
+
Array.from(new URL(options.redirectUri).searchParams, ([key]) => key).some((key) =>
|
|
92
|
+
parameters.has(key),
|
|
93
|
+
)
|
|
94
|
+
)
|
|
91
95
|
return { status: 'failed', reason: 'native-callback-invalid' };
|
|
92
96
|
if (
|
|
93
97
|
['code', 'state', 'error', 'error_description'].some(
|
|
@@ -46,7 +46,7 @@ import Animated, {
|
|
|
46
46
|
withTiming,
|
|
47
47
|
} from 'react-native-reanimated';
|
|
48
48
|
import { useQuery, keepPreviousData } from '@tanstack/react-query';
|
|
49
|
-
import {
|
|
49
|
+
import { ExpoImage } from '../components/ExpoImage';
|
|
50
50
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
51
51
|
import { logger } from '@oxy.so/core';
|
|
52
52
|
import { useOxy } from '../context/oxyRuntimeContext';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useCallback, useMemo } from 'react';
|
|
2
2
|
import { View, StyleSheet, type TextInputProps } from 'react-native';
|
|
3
|
-
import {
|
|
3
|
+
import { ExpoImage } from '../components/ExpoImage';
|
|
4
4
|
import Ionicons from '../icons/Ionicons';
|
|
5
5
|
import type { BaseScreenProps } from '../types/navigation';
|
|
6
6
|
import { useTheme } from '@oxy.so/bloom/theme';
|
|
@@ -8,7 +8,7 @@ import { type ComponentRef, useState, useCallback, useMemo, useRef } from 'react
|
|
|
8
8
|
import { View, StyleSheet, ScrollView, RefreshControl, useWindowDimensions } from 'react-native';
|
|
9
9
|
import { Text } from '@oxy.so/bloom/typography';
|
|
10
10
|
import { useQueryClient } from '@tanstack/react-query';
|
|
11
|
-
import {
|
|
11
|
+
import { ExpoImage } from '../components/ExpoImage';
|
|
12
12
|
import type { FileManagementScreenProps } from '../types/fileManagement';
|
|
13
13
|
import { toast } from '@oxy.so/bloom/toast';
|
|
14
14
|
import { surfaces } from '@oxy.so/bloom/surfaces';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useContext, useState } from 'react';
|
|
2
2
|
import { Linking, View } from 'react-native';
|
|
3
|
-
import {
|
|
3
|
+
import { ExpoImage } from '../components/ExpoImage';
|
|
4
4
|
import { SubscriptionPlans } from '@oxy.so/bloom/subscription-plans';
|
|
5
5
|
import {
|
|
6
6
|
SegmentedControl,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
type LayoutChangeEvent,
|
|
13
13
|
} from 'react-native';
|
|
14
14
|
import { Text } from '@oxy.so/bloom/typography';
|
|
15
|
-
import {
|
|
15
|
+
import { ExpoImage } from '../../components/ExpoImage';
|
|
16
16
|
import Ionicons from '../../icons/Ionicons';
|
|
17
17
|
import MaterialCommunityIcons from '../../icons/MaterialCommunityIcons';
|
|
18
18
|
import type { FileMetadata } from '@oxy.so/core';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-native-macos fork of `imageSize.ts`: expo-image has no macOS
|
|
3
|
+
* implementation (see `components/ExpoImage.macos.tsx`), so the size comes
|
|
4
|
+
* from react-native's `Image.getSize`, which react-native-macos answers through
|
|
5
|
+
* NSImage. Fresco, the reason the Android fork avoids it, is Android-only.
|
|
6
|
+
*/
|
|
7
|
+
import { Image } from 'react-native';
|
|
8
|
+
|
|
9
|
+
export interface ImageSize {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getImageSize(uri: string): Promise<ImageSize> {
|
|
15
|
+
return new Promise<ImageSize>((resolve, reject) => {
|
|
16
|
+
Image.getSize(uri, (width, height) => resolve({ width, height }), reject);
|
|
17
|
+
});
|
|
18
|
+
}
|