From d07daef8cf7a2bfb77ea8e266c1698ff4ae5e00b Mon Sep 17 00:00:00 2001 From: Tolgahan Date: Fri, 26 Jun 2026 17:53:10 +0300 Subject: [PATCH 1/5] feat(android): support API 24 setup-free --- API.md | 6 + CHANGELOG.md | 11 + README.md | 12 +- android/build.gradle | 10 +- .../OmsClientReactNativeSdkModule.kt | 4 +- examples/expo-example/app.json | 10 +- examples/expo-example/package-lock.json | 35 +- examples/expo-example/package.json | 3 +- examples/expo-example/src/App.tsx | 431 ++++++++++++++++-- examples/sdk-example/android/build.gradle | 4 +- .../android/build.gradle | 4 +- package.json | 2 +- 12 files changed, 427 insertions(+), 105 deletions(-) diff --git a/API.md b/API.md index 8c80f6d..d71a57e 100644 --- a/API.md +++ b/API.md @@ -9,6 +9,12 @@ This document describes the public TypeScript API for npm install @0xsequence/oms-react-native-sdk ``` +## Native Requirements + +Android apps need `minSdk` 24 or newer, `compileSdk` 34 or newer, and Java 17 +compile options. The SDK does not require app-level core library desugaring or a +custom Kotlin version override. + ## Client ```ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 416cbc1..86228a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). --- +## [0.1.0-alpha.4] — 2026-06-26 + +### Changed +- Lowered the Android OMS SDK requirement to `minSdk 24`. +- Aligned Android Kotlin, coroutine, and serialization versions with current + React Native and Expo defaults. + +### Fixed +- Removed the need for Expo and bare React Native apps to raise Android + `minSdk`, override Kotlin, or enable core library desugaring for OMS. + ## [0.1.0-alpha.3] — 2026-06-26 ### Added diff --git a/README.md b/README.md index d954eef..460b291 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ See [API.md](./API.md) for the public API surface and TypeScript shapes. ## Native SDK Dependencies The React Native SDK owns its native SDK dependencies. Android resolves -`io.github.0xsequence:oms-client-kotlin-sdk:0.1.0-alpha.3` from Maven, and iOS +`io.github.0xsequence:oms-client-kotlin-sdk:0.1.0-alpha.4` from Maven, and iOS resolves `oms-client-swift-sdk` `0.1.0-alpha.3` from CocoaPods. The React Native wrapper itself is distributed through npm. React Native @@ -159,8 +159,9 @@ on the underlying native SDKs. - Bare React Native apps are supported through normal React Native autolinking. - Expo apps must use a development build, Expo prebuild/EAS Build, or the bare workflow. Expo Go cannot load this SDK because it includes custom native code. -- Android apps need `minSdk 26`, `compileSdk 34` or newer, and Java 17 compile - options. +- Android apps need `minSdk 24`, `compileSdk 34` or newer, and Java 17 compile + options. No app-level core library desugaring or Kotlin version override is + required for OMS. - iOS apps need deployment target 15.0 or newer. - OIDC redirect auth requires the consuming app to configure its own URL scheme or app links. @@ -171,9 +172,8 @@ on the underlying native SDKs. - `examples/trails-actions-example` is the bare React Native demo for OMS wallet flow with Trails action resolution. - `examples/expo-example` is a standalone Expo development-build demo that uses - `expo-web-browser` and the published npm package. It is intentionally - excluded from the root Yarn workspace so it is not linked to the local SDK - source. Its dependency is not updated until this SDK version is published. + `expo-web-browser` and the npm package. It is intentionally excluded from the + root Yarn workspace so it is not linked to the local SDK source. ## Publishing diff --git a/android/build.gradle b/android/build.gradle index da3664c..360af7c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { ext.OmsClientReactNativeSdk = [ - kotlinVersion: "2.3.20", - minSdkVersion: 26, + kotlinVersion: "2.1.20", + minSdkVersion: 24, compileSdkVersion: 36, targetSdkVersion: 36, - omsClientKotlinSdkVersion: "0.1.0-alpha.3", - kotlinxCoroutinesVersion: "1.11.0", - kotlinxSerializationJsonVersion: "1.11.0" + omsClientKotlinSdkVersion: "0.1.0-alpha.4", + kotlinxCoroutinesVersion: "1.10.2", + kotlinxSerializationJsonVersion: "1.8.1" ] ext.getExtOrDefault = { prop -> diff --git a/android/src/main/java/com/omsclientreactnativesdk/OmsClientReactNativeSdkModule.kt b/android/src/main/java/com/omsclientreactnativesdk/OmsClientReactNativeSdkModule.kt index 3c21572..1183b61 100644 --- a/android/src/main/java/com/omsclientreactnativesdk/OmsClientReactNativeSdkModule.kt +++ b/android/src/main/java/com/omsclientreactnativesdk/OmsClientReactNativeSdkModule.kt @@ -98,7 +98,7 @@ class OmsClientReactNativeSdkModule(reactContext: ReactApplicationContext) : Arguments.createMap().apply { putString("clientId", clientId) putMap("session", sessionMap(event.session)) - putString("expiredAt", event.expiredAt.toString()) + putString("expiredAt", event.expiredAt) } ) } @@ -707,7 +707,7 @@ class OmsClientReactNativeSdkModule(reactContext: ReactApplicationContext) : private fun sessionMap(session: OMSClientSessionState?): WritableMap = Arguments.createMap().apply { putNullableString("walletAddress", session?.walletAddress) - putNullableString("expiresAt", session?.expiresAt?.toString()) + putNullableString("expiresAt", session?.expiresAt) putNullableString("loginType", session?.loginType?.name) putNullableString("sessionEmail", session?.sessionEmail) } diff --git a/examples/expo-example/app.json b/examples/expo-example/app.json index 6b7e2ed..440befb 100644 --- a/examples/expo-example/app.json +++ b/examples/expo-example/app.json @@ -14,15 +14,7 @@ "package": "com.sequence.oms.expoexample" }, "plugins": [ - "expo-web-browser", - [ - "expo-build-properties", - { - "android": { - "minSdkVersion": 26 - } - } - ] + "expo-web-browser" ] } } diff --git a/examples/expo-example/package-lock.json b/examples/expo-example/package-lock.json index 588b11e..02a5f37 100644 --- a/examples/expo-example/package-lock.json +++ b/examples/expo-example/package-lock.json @@ -8,9 +8,8 @@ "name": "oms-client-react-native-sdk-expo-example", "version": "0.0.1", "dependencies": { - "@0xsequence/oms-react-native-sdk": "0.1.0-alpha.2", + "@0xsequence/oms-react-native-sdk": "0.1.0-alpha.4", "expo": "~56.0.8", - "expo-build-properties": "~56.0.17", "expo-dev-client": "~56.0.19", "expo-web-browser": "~56.0.5", "react": "19.2.7", @@ -26,9 +25,9 @@ } }, "node_modules/@0xsequence/oms-react-native-sdk": { - "version": "0.1.0-alpha.2", - "resolved": "https://registry.npmjs.org/@0xsequence/oms-react-native-sdk/-/oms-react-native-sdk-0.1.0-alpha.2.tgz", - "integrity": "sha512-OWX/ibaIEd2D9NmINnaqxkIH9uwZjpVHRKAbEcDQvTpxvi1tPcRD6KwvSEMl+6cwB7z+qXxqgb24Pyxfl33sww==", + "version": "0.1.0-alpha.4", + "resolved": "https://registry.npmjs.org/@0xsequence/oms-react-native-sdk/-/oms-react-native-sdk-0.1.0-alpha.4.tgz", + "integrity": "sha512-V7ayhhFroKBOwps/sdFEX9+KqzfpM38DI0lgd5PF0YQHqvM5kiMGofGv2WHzPkbYi4vT1nf0/tgZNBhbHEmjDQ==", "license": "MIT", "workspaces": [ "examples/*", @@ -2749,32 +2748,6 @@ } } }, - "node_modules/expo-build-properties": { - "version": "56.0.17", - "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-56.0.17.tgz", - "integrity": "sha512-qt12qdaxV4FEeFH+X4tM4uoeKNytqJahpmb74VVV/cSKX47RzBRtCyEIAW+tgI6BUTZjnDtBZj0PTyBdlZbB6Q==", - "license": "MIT", - "dependencies": { - "@expo/schema-utils": "^56.0.0", - "resolve-from": "^5.0.0", - "semver": "^7.6.0" - }, - "peerDependencies": { - "expo": "*" - } - }, - "node_modules/expo-build-properties/node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/expo-dev-client": { "version": "56.0.19", "resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-56.0.19.tgz", diff --git a/examples/expo-example/package.json b/examples/expo-example/package.json index 40c13f4..24c2e72 100644 --- a/examples/expo-example/package.json +++ b/examples/expo-example/package.json @@ -12,9 +12,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@0xsequence/oms-react-native-sdk": "0.1.0-alpha.2", + "@0xsequence/oms-react-native-sdk": "0.1.0-alpha.4", "expo": "~56.0.8", - "expo-build-properties": "~56.0.17", "expo-dev-client": "~56.0.19", "expo-web-browser": "~56.0.5", "react": "19.2.7", diff --git a/examples/expo-example/src/App.tsx b/examples/expo-example/src/App.tsx index 82bc8d8..a8aa648 100644 --- a/examples/expo-example/src/App.tsx +++ b/examples/expo-example/src/App.tsx @@ -19,19 +19,12 @@ import { View, } from 'react-native'; import { - completeEmailAuth, - configure, - getSupportedNetworks, - getSession, - sendTransaction, - handleOidcRedirectCallback, + OMSClient, OidcProviders, - signMessage, - signOut, - startEmailAuth, - startOidcRedirectAuth, - verifyMessageSignature, + type OmsClientSessionExpiredEvent, type OmsClientSessionState, + type OmsFeeOptionSelection, + type OmsFeeOptionWithBalance, type OmsNetwork, type OmsPendingWalletSelection, type OmsWallet, @@ -40,16 +33,13 @@ import { WebBrowser.maybeCompleteAuthSession(); -const DEMO_PUBLISHABLE_KEY = 'AQAAAAAAAAK2JvvZhWqZ51riasWBftkrVXE'; -const DEMO_PROJECT_ID = 'proj_014kg56dc0a75'; +const DEMO_PUBLISHABLE_KEY = + 'pk_dev_sdbx_01kqa06hyyetj_01kv5ceg4xefattzmm9fyx04ev'; const DEMO_OIDC_REDIRECT_URI = 'omsclientrndemo://auth/callback'; -const DEMO_ENVIRONMENT = { - apiRpcUrl: 'https://dev-api.sequence.app/rpc/API', - indexerUrlTemplate: 'https://dev-{value}-indexer.sequence.app/rpc/Indexer/', -}; const DEFAULT_TRANSACTION_TO = '0xE5E8B483FfC05967FcFed58cc98D053265af6D99'; const PREFERRED_NETWORK_ORDER = ['80002', '137']; +const DEFAULT_SESSION_LIFETIME_SECONDS = '604800'; const SIGNED_OUT_SESSION: OmsClientSessionState = { walletAddress: null, expiresAt: null, @@ -239,6 +229,77 @@ function WalletSelectionOption({ ); } +function FeeOptionPickerModal({ + options, + visible, + onCancel, + onSelect, +}: { + options: OmsFeeOptionWithBalance[]; + visible: boolean; + onCancel: () => void; + onSelect: (selection: OmsFeeOptionSelection) => void; +}) { + return ( + + + + + Fee Option + + + + `${option.selection.token}-${index}` + } + renderItem={({ item }) => { + const selectable = feeOptionIsSelectable(item); + return ( + onSelect(item.selection)} + style={({ pressed }) => [ + styles.feeOption, + !selectable && styles.buttonDisabled, + pressed && selectable && styles.buttonPressed, + ]} + > + + + {feeOptionTitle(item)} + + + {feeOptionSubtitle(item)} + + + {item.selection.token} + + + + {selectable ? 'Select' : 'Insufficient'} + + + ); + }} + style={styles.networkPickerList} + /> + + + + ); +} + function NetworkPickerModal({ networks, selectedChainId, @@ -304,6 +365,10 @@ function NetworkPickerModal({ } export default function App() { + const oms = useMemo( + () => new OMSClient({ publishableKey: DEMO_PUBLISHABLE_KEY }), + [] + ); const [networks, setNetworks] = useState([]); const [selectedChainId, setSelectedChainId] = useState('80002'); const [sdkReady, setSdkReady] = useState(false); @@ -314,6 +379,11 @@ export default function App() { const [code, setCode] = useState(''); const [authStatus, setAuthStatus] = useState('Waiting for sign-in.'); const [manualWalletSelection, setManualWalletSelection] = useState(false); + const [sessionLifetimeSeconds, setSessionLifetimeSeconds] = useState( + DEFAULT_SESSION_LIFETIME_SECONDS + ); + const [expiredSessionEvent, setExpiredSessionEvent] = + useState(null); const [pendingWalletSelection, setPendingWalletSelection] = useState(null); const [message, setMessage] = useState('test'); @@ -335,8 +405,14 @@ export default function App() { const [networkPickerVisible, setNetworkPickerVisible] = useState(false); const [logLines, setLogLines] = useState(['Ready.']); const [loadingAction, setLoadingAction] = useState(null); + const [feeOptionPickerOptions, setFeeOptionPickerOptions] = useState< + OmsFeeOptionWithBalance[] + >([]); const handledRedirectUrlsRef = useRef(new Set()); const handlingRedirectUrlRef = useRef(null); + const feeOptionSelectionResolverRef = useRef< + ((selection: OmsFeeOptionSelection | null) => void) | null + >(null); const selectedNetwork = useMemo( () => @@ -349,16 +425,67 @@ export default function App() { setLogLines((current) => [...current, messageToAppend].slice(-80)); }, []); + const resolveFeeOptionSelection = useCallback( + (selection: OmsFeeOptionSelection | null) => { + const resolver = feeOptionSelectionResolverRef.current; + feeOptionSelectionResolverRef.current = null; + setFeeOptionPickerOptions([]); + resolver?.(selection); + }, + [] + ); + + const selectFeeOption = useCallback( + async ( + feeOptions: OmsFeeOptionWithBalance[] + ): Promise => { + if (feeOptions.length === 0) { + appendLog('No fee options available.'); + return null; + } + + feeOptionSelectionResolverRef.current?.(null); + setFeeOptionPickerOptions(feeOptions); + appendLog(`Fee options available: ${feeOptions.length}`); + + return new Promise((resolve) => { + feeOptionSelectionResolverRef.current = resolve; + }); + }, + [appendLog] + ); + + const chooseFeeOption = useCallback( + (selection: OmsFeeOptionSelection) => { + appendLog(`Selected fee option: ${selection.token}`); + resolveFeeOptionSelection(selection); + }, + [appendLog, resolveFeeOptionSelection] + ); + + const cancelFeeOptionSelection = useCallback(() => { + appendLog('Fee option selection cancelled.'); + resolveFeeOptionSelection(null); + }, [appendLog, resolveFeeOptionSelection]); + + useEffect(() => { + return () => { + feeOptionSelectionResolverRef.current?.(null); + feeOptionSelectionResolverRef.current = null; + }; + }, []); + const refreshSession = useCallback(async () => { - const nextSession = await getSession(); + const nextSession = await oms.wallet.getSession(); setSession(nextSession); if (nextSession.walletAddress) { + setExpiredSessionEvent(null); setAuthStatus('Restored persisted wallet session'); setSignatureStatus('Signature status: ready to sign.'); setTransactionStatus('Transaction status: ready to send.'); } return nextSession; - }, []); + }, [oms]); const runAction = useCallback( async ( @@ -380,10 +507,49 @@ export default function App() { [appendLog] ); + const requestedSessionLifetimeSeconds = useCallback( + () => parseSessionLifetimeSeconds(sessionLifetimeSeconds), + [sessionLifetimeSeconds] + ); + + const clearExpiredSessionState = useCallback(() => { + setExpiredSessionEvent(null); + }, []); + + const handleSessionExpired = useCallback( + (event: OmsClientSessionExpiredEvent) => { + const emailHint = expiredSessionEmail(event); + + setExpiredSessionEvent(event); + setSession(SIGNED_OUT_SESSION); + setPendingWalletSelection(null); + setCode(''); + setAuthStage('email'); + setAuthStatus( + emailHint + ? `Wallet session expired. Sign in again as ${emailHint}.` + : 'Wallet session expired. Sign in again.' + ); + if (emailHint) { + setEmail(emailHint); + } + setLastSignedMessage(null); + setLastSignature(null); + setLastTransactionHash(null); + setSignatureStatus('Signature status: waiting for reauth.'); + setTransactionStatus('Transaction status: waiting for reauth.'); + appendLog( + `Wallet session expired at ${event.expiredAt}: wallet=${event.session.walletAddress ?? 'none'} email=${event.session.sessionEmail ?? 'none'}` + ); + }, + [appendLog] + ); + const activateWallet = useCallback( async (result: OmsWalletActivationResult) => { - const nextSession = await getSession(); + const nextSession = await oms.wallet.getSession(); const address = nextSession.walletAddress ?? result.walletAddress; + clearExpiredSessionState(); setPendingWalletSelection(null); setCode(''); setAuthStage('email'); @@ -397,7 +563,7 @@ export default function App() { setTransactionStatus('Transaction status: ready to send.'); appendLog(`Wallet ready: ${address}`); }, - [appendLog] + [appendLog, clearExpiredSessionState, oms] ); const finishOidcRedirectSignIn = useCallback( @@ -410,12 +576,15 @@ export default function App() { } handlingRedirectUrlRef.current = callbackUrl; + let callbackHandled = false; try { setAuthStatus('Completing Google redirect sign-in...'); - const result = await handleOidcRedirectCallback({ + const result = await oms.wallet.handleOidcRedirectCallback({ callbackUrl, walletSelection: manualWalletSelection ? 'manual' : 'automatic', + sessionLifetimeSeconds: requestedSessionLifetimeSeconds(), }); + callbackHandled = true; switch (result.type) { case 'completed': @@ -448,11 +617,20 @@ export default function App() { break; } } finally { - handledRedirectUrlsRef.current.add(callbackUrl); + if (callbackHandled) { + handledRedirectUrlsRef.current.add(callbackUrl); + } handlingRedirectUrlRef.current = null; } }, - [activateWallet, appendLog, manualWalletSelection, refreshSession] + [ + activateWallet, + appendLog, + manualWalletSelection, + oms, + refreshSession, + requestedSessionLifetimeSeconds, + ] ); const selectNetwork = useCallback( @@ -476,13 +654,7 @@ export default function App() { async function bootstrap() { await runAction('Initializing SDK', async () => { - await configure({ - publishableKey: DEMO_PUBLISHABLE_KEY, - projectId: DEMO_PROJECT_ID, - environment: DEMO_ENVIRONMENT, - }); - - const supportedNetworks = sortNetworks(await getSupportedNetworks()); + const supportedNetworks = sortNetworks(oms.supportedNetworks); if (disposed) return; setNetworks(supportedNetworks); @@ -502,11 +674,13 @@ export default function App() { return () => { disposed = true; }; - }, [appendLog, refreshSession, runAction]); + }, [appendLog, oms, refreshSession, runAction]); useEffect(() => { if (!sdkReady) return undefined; + const sessionExpiredSubscription = + oms.wallet.onSessionExpired(handleSessionExpired); const subscription = Linking.addEventListener('url', ({ url }) => { if (isDemoOidcRedirectUrl(url)) { runAction( @@ -539,8 +713,18 @@ export default function App() { appendLog(`!! ${describeError(error)}`); }); - return () => subscription.remove(); - }, [appendLog, finishOidcRedirectSignIn, runAction, sdkReady]); + return () => { + sessionExpiredSubscription.remove(); + subscription.remove(); + }; + }, [ + appendLog, + finishOidcRedirectSignIn, + handleSessionExpired, + oms, + runAction, + sdkReady, + ]); const walletAddress = session.walletAddress; const isSignedIn = walletAddress != null; @@ -550,13 +734,18 @@ export default function App() { runAction( 'Start email sign-in', async () => { - const normalizedEmail = requireText(email, 'Email'); + const normalizedEmail = email.trim(); setAuthStatus('Requesting email code...'); setPendingWalletSelection(null); - await startEmailAuth(normalizedEmail); + const emailForSignIn = + normalizedEmail || expiredSessionEmail(expiredSessionEvent); + if (!emailForSignIn) { + throw new Error('Email is required'); + } + await oms.wallet.startEmailAuth(emailForSignIn); setEmail(''); setAuthStage('code'); - setAuthStatus(`Code requested for ${normalizedEmail}`); + setAuthStatus(`Code requested for ${emailForSignIn}`); }, (error) => { setAuthStatus(`Email sign-in failed: ${describeError(error)}`); @@ -569,9 +758,10 @@ export default function App() { 'Confirm code and resolve wallet', async () => { setAuthStatus('Confirming code and resolving wallet...'); - const authResult = await completeEmailAuth({ + const authResult = await oms.wallet.completeEmailAuth({ code: requireText(code, 'Verification code'), walletSelection: manualWalletSelection ? 'manual' : 'automatic', + sessionLifetimeSeconds: requestedSessionLifetimeSeconds(), }); if (authResult.type === 'walletSelection') { @@ -600,9 +790,11 @@ export default function App() { async () => { setPendingWalletSelection(null); setAuthStatus('Opening Google redirect sign-in...'); - const started = await startOidcRedirectAuth({ + requestedSessionLifetimeSeconds(); + const started = await oms.wallet.startOidcRedirectAuth({ provider: OidcProviders.google(), redirectUri: DEMO_OIDC_REDIRECT_URI, + loginHint: expiredSessionEmail(expiredSessionEvent), }); appendLog(`Google redirect auth started: state=${started.state}`); @@ -629,7 +821,8 @@ export default function App() { const cancelCodeStep = () => { runAction('Cancel email code step', async () => { - await signOut(); + await oms.wallet.signOut(); + clearExpiredSessionState(); setSession(SIGNED_OUT_SESSION); setCode(''); setPendingWalletSelection(null); @@ -670,7 +863,8 @@ export default function App() { const logout = () => { runAction('Logout', async () => { - await signOut(); + await oms.wallet.signOut(); + clearExpiredSessionState(); setSession(SIGNED_OUT_SESSION); setAuthStage('email'); setPendingWalletSelection(null); @@ -691,7 +885,10 @@ export default function App() { const network = requireNetwork(selectedNetwork); const nextMessage = requireText(message, 'Message'); setSignatureStatus('Signature status: signing in progress...'); - const signature = await signMessage(network.chainId, nextMessage); + const signature = await oms.wallet.signMessage( + network.chainId, + nextMessage + ); setLastSignedMessage(nextMessage); setLastSignature(signature); setSignatureStatus('Signature status: signed. Ready to verify.'); @@ -711,7 +908,7 @@ export default function App() { const signedMessage = requireText(lastSignedMessage, 'Signed message'); const signature = requireText(lastSignature, 'Signature'); setSignatureStatus('Signature status: verification in progress...'); - const isValid = await verifyMessageSignature({ + const isValid = await oms.wallet.verifyMessageSignature({ chainId: network.chainId, message: signedMessage, signature, @@ -735,10 +932,11 @@ export default function App() { async () => { const network = requireNetwork(selectedNetwork); setTransactionStatus('Transaction status: sending in progress...'); - const txResult = await sendTransaction({ + const txResult = await oms.wallet.sendTransaction({ chainId: network.chainId, to: requireText(transactionTo, 'Transaction destination'), value: decimalToBaseUnits(transactionValue, 18), + selectFeeOption, }); setLastTransactionHash(txResult.txnHash); setTransactionStatus( @@ -782,7 +980,6 @@ export default function App() { Auth Demo OMS Client React Native SDK - Expo example {authStatus} + {expiredSessionEvent ? ( + + + + + + ) : null} {pendingWalletSelection ? ( Finish sign-in by selecting a wallet below. @@ -809,6 +1030,17 @@ export default function App() { setManualWalletSelection((current) => !current) } /> + + !current) } /> + Verification Code + 0} + /> setNetworkPickerVisible(false)} @@ -1058,6 +1302,68 @@ function requireText(value: string | null, label: string): string { return trimmed; } +function parseSessionLifetimeSeconds(value: string): number | null { + const trimmed = value.trim(); + if (!trimmed) { + return null; + } + + if (!/^\d+$/.test(trimmed)) { + throw new Error('Session lifetime seconds must be a positive whole number'); + } + + const parsed = Number(trimmed); + if (!Number.isSafeInteger(parsed) || parsed <= 0) { + throw new Error('Session lifetime seconds must be a positive whole number'); + } + + return parsed; +} + +function expiredSessionEmail( + event: OmsClientSessionExpiredEvent | null +): string | null { + const email = event?.session.sessionEmail?.trim(); + return email ? email : null; +} + +function feeOptionTitle(option: OmsFeeOptionWithBalance): string { + const symbol = feeOptionSymbol(option); + return `${symbol} fee`; +} + +function feeOptionSubtitle(option: OmsFeeOptionWithBalance): string { + const symbol = feeOptionSymbol(option); + const fee = `${option.feeOption.displayValue} ${symbol}`; + const available = option.available + ? `${option.available} ${symbol}` + : 'unknown'; + + return `Fee ${fee} · Available ${available}`; +} + +function feeOptionSymbol(option: OmsFeeOptionWithBalance): string { + return option.feeOption.token.symbol || option.selection.token; +} + +function feeOptionIsSelectable(option: OmsFeeOptionWithBalance): boolean { + const available = optionalBigInt(option.availableRaw); + const fee = optionalBigInt(option.feeOption.value); + return available == null || fee == null || available >= fee; +} + +function optionalBigInt(value: string | null | undefined): bigint | null { + if (!value) { + return null; + } + + try { + return BigInt(value); + } catch { + return null; + } +} + function formatLoginType( loginType: OmsClientSessionState['loginType'] ): string { @@ -1182,6 +1488,10 @@ const styles = StyleSheet.create({ fontWeight: '600', textTransform: 'uppercase', }, + fieldSeparator: { + backgroundColor: '#303644', + height: 1, + }, input: { backgroundColor: '#0B0D12', borderColor: '#303644', @@ -1357,6 +1667,37 @@ const styles = StyleSheet.create({ color: '#94A3B8', fontSize: 12, }, + feeOption: { + alignItems: 'center', + borderColor: '#303644', + borderRadius: 8, + borderWidth: 1, + flexDirection: 'row', + gap: 12, + justifyContent: 'space-between', + marginBottom: 10, + padding: 12, + }, + feeOptionText: { + flex: 1, + gap: 4, + }, + feeOptionTitle: { + color: '#F8FAFC', + fontSize: 15, + fontWeight: '700', + }, + feeOptionSubtitle: { + color: '#CBD5E1', + fontSize: 12, + lineHeight: 17, + }, + feeOptionToken: { + color: '#94A3B8', + fontFamily: Platform.select({ ios: 'Menlo', android: 'monospace' }), + fontSize: 11, + lineHeight: 16, + }, status: { color: '#CBD5E1', fontSize: 13, diff --git a/examples/sdk-example/android/build.gradle b/examples/sdk-example/android/build.gradle index 57d4e85..fcaece1 100644 --- a/examples/sdk-example/android/build.gradle +++ b/examples/sdk-example/android/build.gradle @@ -1,11 +1,11 @@ buildscript { ext { buildToolsVersion = "36.0.0" - minSdkVersion = 26 + minSdkVersion = 24 compileSdkVersion = 36 targetSdkVersion = 36 ndkVersion = "27.1.12297006" - kotlinVersion = "2.3.20" + kotlinVersion = "2.1.20" } repositories { mavenLocal() diff --git a/examples/trails-actions-example/android/build.gradle b/examples/trails-actions-example/android/build.gradle index 57d4e85..fcaece1 100644 --- a/examples/trails-actions-example/android/build.gradle +++ b/examples/trails-actions-example/android/build.gradle @@ -1,11 +1,11 @@ buildscript { ext { buildToolsVersion = "36.0.0" - minSdkVersion = 26 + minSdkVersion = 24 compileSdkVersion = 36 targetSdkVersion = 36 ndkVersion = "27.1.12297006" - kotlinVersion = "2.3.20" + kotlinVersion = "2.1.20" } repositories { mavenLocal() diff --git a/package.json b/package.json index 23502b1..97f12d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@0xsequence/oms-react-native-sdk", - "version": "0.1.0-alpha.3", + "version": "0.1.0-alpha.4", "description": "React Native SDK for the OMS platform.", "homepage": "https://github.com/0xsequence/react-native-sdk", "main": "./lib/commonjs/index.js", From aff3ce531f45c5f8a754db3f28f6bc91e146c174 Mon Sep 17 00:00:00 2001 From: Tolgahan Date: Wed, 1 Jul 2026 16:22:26 +0300 Subject: [PATCH 2/5] fix: align alpha.4 native sdk setup --- .github/workflows/ci.yml | 2 +- .github/workflows/quick-checks.yml | 2 +- API.md | 5 +-- CHANGELOG.md | 6 ++- OmsClientReactNativeSdk.podspec | 2 +- README.md | 8 ++-- TESTING.md | 3 +- examples/expo-example/package-lock.json | 2 +- examples/expo-example/src/App.tsx | 1 + examples/sdk-example/ios/Podfile.lock | 10 ++--- .../trails-actions-example/ios/Podfile.lock | 10 ++--- ios/OmsClientReactNativeSdkImpl.swift | 42 ++++++++++++++----- package.json | 1 + scripts/install-expo-example-dependencies.sh | 32 ++++++++++++++ 14 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 scripts/install-expo-example-dependencies.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1fcb33..031fee6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: run: yarn lint - name: Install Expo example dependencies - run: npm --prefix examples/expo-example ci + run: yarn expo-example:install - name: Typecheck files run: yarn typecheck diff --git a/.github/workflows/quick-checks.yml b/.github/workflows/quick-checks.yml index 29d4e41..17b8063 100644 --- a/.github/workflows/quick-checks.yml +++ b/.github/workflows/quick-checks.yml @@ -28,7 +28,7 @@ jobs: run: yarn lint - name: Install Expo example dependencies - run: npm --prefix examples/expo-example ci + run: yarn expo-example:install - name: Typecheck files run: yarn typecheck diff --git a/API.md b/API.md index d71a57e..cc723d1 100644 --- a/API.md +++ b/API.md @@ -11,9 +11,8 @@ npm install @0xsequence/oms-react-native-sdk ## Native Requirements -Android apps need `minSdk` 24 or newer, `compileSdk` 34 or newer, and Java 17 -compile options. The SDK does not require app-level core library desugaring or a -custom Kotlin version override. +Android builds need `minSdk` 24 or newer, `compileSdk` 34 or newer, and Java 17 +compile options. Supported Android devices need Android 10 / API 29 or newer. ## Client diff --git a/CHANGELOG.md b/CHANGELOG.md index 86228a7..95180e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,12 @@ Versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Lowered the Android OMS SDK requirement to `minSdk 24`. - Aligned Android Kotlin, coroutine, and serialization versions with current React Native and Expo defaults. +- Updated the iOS OMS SDK dependency to `0.1.0-alpha.4`. +- Aligned iOS promise rejection metadata with the current native error contract. ### Fixed -- Removed the need for Expo and bare React Native apps to raise Android - `minSdk`, override Kotlin, or enable core library desugaring for OMS. +- Expo and bare React Native apps can use the standard Android build + requirements for OMS. ## [0.1.0-alpha.3] — 2026-06-26 diff --git a/OmsClientReactNativeSdk.podspec b/OmsClientReactNativeSdk.podspec index 2b3858b..5ee0431 100644 --- a/OmsClientReactNativeSdk.podspec +++ b/OmsClientReactNativeSdk.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift,cpp}" s.private_header_files = "ios/**/*.h" s.swift_version = "6.0" - s.dependency "oms-client-swift-sdk", "0.1.0-alpha.3" + s.dependency "oms-client-swift-sdk", "0.1.0-alpha.4" s.pod_target_xcconfig = { "DEFINES_MODULE" => "YES" } diff --git a/README.md b/README.md index 460b291..2eb64cd 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ See [API.md](./API.md) for the public API surface and TypeScript shapes. The React Native SDK owns its native SDK dependencies. Android resolves `io.github.0xsequence:oms-client-kotlin-sdk:0.1.0-alpha.4` from Maven, and iOS -resolves `oms-client-swift-sdk` `0.1.0-alpha.3` from CocoaPods. +resolves `oms-client-swift-sdk` `0.1.0-alpha.4` from CocoaPods. The React Native wrapper itself is distributed through npm. React Native autolinking consumes the wrapper podspec and Android project from @@ -159,9 +159,9 @@ on the underlying native SDKs. - Bare React Native apps are supported through normal React Native autolinking. - Expo apps must use a development build, Expo prebuild/EAS Build, or the bare workflow. Expo Go cannot load this SDK because it includes custom native code. -- Android apps need `minSdk 24`, `compileSdk 34` or newer, and Java 17 compile - options. No app-level core library desugaring or Kotlin version override is - required for OMS. +- Android builds need `minSdk 24`, `compileSdk 34` or newer, and Java 17 compile + options. +- Supported Android devices need Android 10 / API 29 or newer. - iOS apps need deployment target 15.0 or newer. - OIDC redirect auth requires the consuming app to configure its own URL scheme or app links. diff --git a/TESTING.md b/TESTING.md index 805b2b7..33737b7 100644 --- a/TESTING.md +++ b/TESTING.md @@ -27,7 +27,7 @@ yarn typecheck yarn test # TypeScript type-check (Expo example) -npm --prefix examples/expo-example ci +yarn expo-example:install npm --prefix examples/expo-example run typecheck # Build the library @@ -72,6 +72,7 @@ Android and iOS CI checks pass before merging; validate locally when you need fa |-----------------------------|----------------------------------------------| | Lint | `yarn lint` | | Typecheck (library) | `yarn typecheck` | +| Install Expo example deps | `yarn expo-example:install` | | Typecheck (Expo example) | `npm --prefix examples/expo-example run typecheck` | | Build library | `yarn prepare` | | Run unit tests | `yarn test` | diff --git a/examples/expo-example/package-lock.json b/examples/expo-example/package-lock.json index 02a5f37..f48e4c8 100644 --- a/examples/expo-example/package-lock.json +++ b/examples/expo-example/package-lock.json @@ -27,7 +27,7 @@ "node_modules/@0xsequence/oms-react-native-sdk": { "version": "0.1.0-alpha.4", "resolved": "https://registry.npmjs.org/@0xsequence/oms-react-native-sdk/-/oms-react-native-sdk-0.1.0-alpha.4.tgz", - "integrity": "sha512-V7ayhhFroKBOwps/sdFEX9+KqzfpM38DI0lgd5PF0YQHqvM5kiMGofGv2WHzPkbYi4vT1nf0/tgZNBhbHEmjDQ==", + "integrity": "sha512-AtvA+ATjtTtut+1R25ODMi/nFugvgkN4dgt3D1JO0IiokQXyIkqyYO4IyrSbLCAxZcpXtglimvPWcdvGXZC8/w==", "license": "MIT", "workspaces": [ "examples/*", diff --git a/examples/expo-example/src/App.tsx b/examples/expo-example/src/App.tsx index a8aa648..0a69095 100644 --- a/examples/expo-example/src/App.tsx +++ b/examples/expo-example/src/App.tsx @@ -980,6 +980,7 @@ export default function App() { Auth Demo OMS Client React Native SDK + Expo example [String: Any] { + [ + "service": error.service.rawValue, + "name": error.name ?? NSNull(), + "code": error.code ?? NSNull(), + "message": error.message ?? NSNull(), + "status": nullableNumber(error.status) + ] + } + + private func nullableNumber(_ value: Int?) -> Any { + guard let value else { return NSNull() } + return NSNumber(value: value) + } + + private func nullableBool(_ value: Bool?) -> Any { + guard let value else { return NSNull() } + return NSNumber(value: value) + } + + private func nullableUpstreamError(_ error: OmsUpstreamError?) -> Any { + guard let error else { return NSNull() } + return upstreamErrorDictionary(error) + } } private final class ClientBox: @unchecked Sendable { diff --git a/package.json b/package.json index 97f12d9..8f02959 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "expo-example": "cd examples/expo-example && npm start", "expo-example:android": "cd examples/expo-example && npm run android", "expo-example:ios": "cd examples/expo-example && npm run ios", + "expo-example:install": "bash scripts/install-expo-example-dependencies.sh", "clean": "del-cli android/build examples/sdk-example/android/build examples/sdk-example/android/app/build examples/sdk-example/ios/build examples/trails-actions-example/android/build examples/trails-actions-example/android/app/build examples/trails-actions-example/ios/build lib", "prepare": "bob build", "test": "yarn prepare && node --test test/*.test.js", diff --git a/scripts/install-expo-example-dependencies.sh b/scripts/install-expo-example-dependencies.sh new file mode 100644 index 0000000..701437d --- /dev/null +++ b/scripts/install-expo-example-dependencies.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +EXPO_DIR="$ROOT_DIR/examples/expo-example" +PACKAGE_NAME="$(cd "$ROOT_DIR" && node -p "require('./package.json').name")" +PACKAGE_VERSION="$(cd "$ROOT_DIR" && node -p "require('./package.json').version")" +PACKAGE_SPEC="$PACKAGE_NAME@$PACKAGE_VERSION" + +if npm view "$PACKAGE_SPEC" version >/dev/null 2>&1; then + npm --prefix "$EXPO_DIR" ci + exit 0 +fi + +TMP_DIR="$(mktemp -d)" +restore_manifest() { + cp "$TMP_DIR/package.json" "$EXPO_DIR/package.json" + cp "$TMP_DIR/package-lock.json" "$EXPO_DIR/package-lock.json" + rm -rf "$TMP_DIR" +} +trap restore_manifest EXIT + +cp "$EXPO_DIR/package.json" "$TMP_DIR/package.json" +cp "$EXPO_DIR/package-lock.json" "$TMP_DIR/package-lock.json" + +TARBALL="$TMP_DIR/oms-react-native-sdk-$PACKAGE_VERSION.tgz" + +cd "$ROOT_DIR" +yarn prepare +yarn pack --out "$TARBALL" +npm --prefix "$EXPO_DIR" install --package-lock-only --ignore-scripts "$TARBALL" +npm --prefix "$EXPO_DIR" ci From c4a11f5d95e1b461fcd0d633ac4428df7c0f6c2e Mon Sep 17 00:00:00 2001 From: Tolgahan Date: Wed, 1 Jul 2026 18:03:45 +0300 Subject: [PATCH 3/5] chore(deps): update trails example dependencies --- examples/trails-actions-example/package.json | 4 +- package.json | 5 - yarn.lock | 101 ++++++++++++------- 3 files changed, 67 insertions(+), 43 deletions(-) diff --git a/examples/trails-actions-example/package.json b/examples/trails-actions-example/package.json index 50bbac7..b973d1d 100644 --- a/examples/trails-actions-example/package.json +++ b/examples/trails-actions-example/package.json @@ -10,9 +10,9 @@ "build:ios": "react-native build-ios --mode Debug" }, "dependencies": { - "0xtrails": "0.16.0", + "0xtrails": "0.16.2", "@0xsequence/oms-react-native-sdk": "workspace:*", - "@0xtrails/api": "0.16.0", + "@0xtrails/api": "0.16.2", "react": "19.2.3", "react-native": "0.85.3", "react-native-inappbrowser-reborn": "3.7.1", diff --git a/package.json b/package.json index 8f02959..837c39b 100644 --- a/package.json +++ b/package.json @@ -90,11 +90,6 @@ "react": "*", "react-native": "*" }, - "resolutions": { - "0xtrails": "0.16.0", - "@0xtrails/api": "0.16.0", - "@0xtrails/wallet": "0.16.0" - }, "workspaces": [ "examples/*", "!examples/expo-example" diff --git a/yarn.lock b/yarn.lock index 42e9ccd..00ccb10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,15 +5,15 @@ __metadata: version: 8 cacheKey: 10c0 -"0xtrails@npm:0.16.0": - version: 0.16.0 - resolution: "0xtrails@npm:0.16.0" +"0xtrails@npm:0.16.2": + version: 0.16.2 + resolution: "0xtrails@npm:0.16.2" dependencies: "@0xsequence/indexer": "npm:^3.0.4" "@0xsequence/metadata": "npm:^3.0.4" "@0xsequence/wallet-primitives": "npm:3.0.0-beta.19" - "@0xtrails/api": "npm:0.16.0" - "@0xtrails/wallet": "npm:0.16.0" + "@0xtrails/api": "npm:0.16.2" + "@0xtrails/wallet": "npm:0.16.2" "@databeat/tracker": "npm:0.9.3" "@emotion/is-prop-valid": "npm:1.4.0" "@meshconnect/web-link-sdk": "npm:3.7.1" @@ -30,7 +30,7 @@ __metadata: react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 viem: ^2.41.0 - checksum: 10c0/ba22b6f09df75078360952eb2738fd4b23f7dda9cdc5d44544d3e3f28e1209b0da0a62a46cdf9d98bcdc09678aeb41e01fc7d770ad4d6cbf59e8899871eb5a4c + checksum: 10c0/93cf79f80e46f29e6c96359ff3c0a43761f3aba7bb2d27e7aaa5bf4a49d5fcf9f8841195f81c4febea912445e72b3604248aea42f3b41a724c5dbc541b0c8a35 languageName: node linkType: hard @@ -84,16 +84,16 @@ __metadata: languageName: node linkType: hard -"@0xtrails/api@npm:0.16.0": - version: 0.16.0 - resolution: "@0xtrails/api@npm:0.16.0" - checksum: 10c0/ac4f33aca737bda4a5407b191a9144738f9ffa7321e23092b7ef5dfba4be1bffd106922dbfa90031644818deb2a9c11cfcc71f45090a993f28338d5ec0ecb0c1 +"@0xtrails/api@npm:0.16.2": + version: 0.16.2 + resolution: "@0xtrails/api@npm:0.16.2" + checksum: 10c0/3e3adc3cc352b0ca492c4b6edb37a6f83ba6e87ac12ec8f10b706fb36020296a15233c25417bceb0993f225db443458a00305e98dffd9261472c33c90f77912e languageName: node linkType: hard -"@0xtrails/wallet@npm:0.16.0": - version: 0.16.0 - resolution: "@0xtrails/wallet@npm:0.16.0" +"@0xtrails/wallet@npm:0.16.2": + version: 0.16.2 + resolution: "@0xtrails/wallet@npm:0.16.2" dependencies: "@base-org/account": "npm:2.4.0" "@safe-global/safe-apps-provider": "npm:0.18.6" @@ -104,7 +104,7 @@ __metadata: "@tanstack/react-query": ^5.90.20 react: ^18.0.0 || ^19.0.0 viem: ^2.41.0 - checksum: 10c0/ed8faaf189aa132f988777264689091a125889f0d6e8597f529de4b47e6ce66bfd899fd651d0ffcb144001384fdc247f91ff058217c21252b0cbf9887d20b475 + checksum: 10c0/078b3095af78e4955e87f0dd48c0ce8f77381bbb536589e50e7211903911f55ef87f9d4e8e806e9f55cbeb59b2506f45f6f581e0fb50cab5bc38d0a1390fbb01 languageName: node linkType: hard @@ -2587,11 +2587,11 @@ __metadata: linkType: hard "@meshconnect/node-api@npm:^2.0.24": - version: 2.0.25 - resolution: "@meshconnect/node-api@npm:2.0.25" + version: 2.0.27 + resolution: "@meshconnect/node-api@npm:2.0.27" dependencies: - axios: "npm:1.15.0" - checksum: 10c0/a8db2dce368920a5de06ecd0e3a6dace39ce841a1b523ae034e260237cb53a2211453ffd6429ca24383a92c798f8bbe0ae3469c970209464a89d4f7f1e91a52d + axios: "npm:1.18.0" + checksum: 10c0/d86a965f46928bcab3e778510d10959ea8724e36b5ec25a16d9c1a50858066f4beeed5222e4a50e91120e780d314a9eb26d24f105e22116d7d8a740afe861035 languageName: node linkType: hard @@ -5561,6 +5561,15 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:6": + version: 6.0.2 + resolution: "agent-base@npm:6.0.2" + dependencies: + debug: "npm:4" + checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 + languageName: node + linkType: hard + "agent-base@npm:^7.1.2": version: 7.1.4 resolution: "agent-base@npm:7.1.4" @@ -5874,25 +5883,26 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.15.0": - version: 1.15.0 - resolution: "axios@npm:1.15.0" +"axios@npm:1.16.0": + version: 1.16.0 + resolution: "axios@npm:1.16.0" dependencies: - follow-redirects: "npm:^1.15.11" + follow-redirects: "npm:^1.16.0" form-data: "npm:^4.0.5" proxy-from-env: "npm:^2.1.0" - checksum: 10c0/47e0f860e98d4d7aa145e89ce0cae00e1fb0f1d2485f065c21fce955ddb1dba4103a46bd0e47acd18a27208a7f62c96249e620db575521b92a968619ab133409 + checksum: 10c0/1c91a5221b77b76072026b4cc95ecdf38f7c3e33e63423abec09a85e6e9a12279637dcc9ac2ba1fc333e0c447fb3b0f46d7965acb5d7cea02d188e9c6d425c0b languageName: node linkType: hard -"axios@npm:1.16.0": - version: 1.16.0 - resolution: "axios@npm:1.16.0" +"axios@npm:1.18.0": + version: 1.18.0 + resolution: "axios@npm:1.18.0" dependencies: follow-redirects: "npm:^1.16.0" form-data: "npm:^4.0.5" + https-proxy-agent: "npm:^5.0.1" proxy-from-env: "npm:^2.1.0" - checksum: 10c0/1c91a5221b77b76072026b4cc95ecdf38f7c3e33e63423abec09a85e6e9a12279637dcc9ac2ba1fc333e0c447fb3b0f46d7965acb5d7cea02d188e9c6d425c0b + checksum: 10c0/f88aae13fd9dd395dea3053c7299178fee62f436f20424a1d6d79ec11ffb7656ba664b4630defbadab2c387b6ea07e29afb9f28b26d8e0e49d45be766983290d languageName: node linkType: hard @@ -7838,7 +7848,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.15.11, follow-redirects@npm:^1.16.0": +"follow-redirects@npm:^1.16.0": version: 1.16.0 resolution: "follow-redirects@npm:1.16.0" peerDependenciesMeta: @@ -7858,15 +7868,15 @@ __metadata: linkType: hard "form-data@npm:^4.0.5": - version: 4.0.5 - resolution: "form-data@npm:4.0.5" + version: 4.0.6 + resolution: "form-data@npm:4.0.6" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" es-set-tostringtag: "npm:^2.1.0" - hasown: "npm:^2.0.2" - mime-types: "npm:^2.1.12" - checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b + hasown: "npm:^2.0.4" + mime-types: "npm:^2.1.35" + checksum: 10c0/43947a77bf0ff45c6ceed789778982d47a3f3e720a74b71721174ebf3310a5f1a8be1d6b38a3ee3688e8a18a2c4273073ec0844cd37efda3eaf46d41c9c318ff languageName: node linkType: hard @@ -8221,6 +8231,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.4": + version: 2.0.4 + resolution: "hasown@npm:2.0.4" + dependencies: + function-bind: "npm:^1.1.2" + checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506 + languageName: node + linkType: hard + "hermes-compiler@npm:250829098.0.10": version: 250829098.0.10 resolution: "hermes-compiler@npm:250829098.0.10" @@ -8305,6 +8324,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^5.0.1": + version: 5.0.1 + resolution: "https-proxy-agent@npm:5.0.1" + dependencies: + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 + languageName: node + linkType: hard + "https-proxy-agent@npm:^7.0.5": version: 7.0.6 resolution: "https-proxy-agent@npm:7.0.6" @@ -9674,7 +9703,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:~2.1.34": +"mime-types@npm:^2.1.35, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -10110,9 +10139,9 @@ __metadata: version: 0.0.0-use.local resolution: "oms-client-react-native-sdk-trails-actions-example@workspace:examples/trails-actions-example" dependencies: - 0xtrails: "npm:0.16.0" + 0xtrails: "npm:0.16.2" "@0xsequence/oms-react-native-sdk": "workspace:*" - "@0xtrails/api": "npm:0.16.0" + "@0xtrails/api": "npm:0.16.2" "@babel/core": "npm:^7.25.2" "@babel/plugin-transform-export-namespace-from": "npm:^7.27.1" "@babel/preset-env": "npm:^7.25.3" From 53e04d04c2ddf84533f5367389e9ff2200ef6a84 Mon Sep 17 00:00:00 2001 From: Tolgahan Date: Wed, 1 Jul 2026 18:18:29 +0300 Subject: [PATCH 4/5] docs(expo): update install instructions --- examples/expo-example/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/expo-example/README.md b/examples/expo-example/README.md index 863a26f..ea776be 100644 --- a/examples/expo-example/README.md +++ b/examples/expo-example/README.md @@ -4,12 +4,8 @@ Expo development-build example for `@0xsequence/oms-react-native-sdk`. This app mirrors the SDK demo flow with email login, Google redirect login, wallet selection, message signing, signature verification, and transaction -sending. It uses `expo-web-browser` for redirect auth and depends on the -published npm package: - -```json -"@0xsequence/oms-react-native-sdk": "0.1.0-alpha.2" -``` +sending. It uses `expo-web-browser` for redirect auth and depends on the SDK +version declared in `package.json`. This example is intentionally excluded from the root Yarn workspace. It is not linked to the local SDK package, which keeps it useful as a consumer-style smoke @@ -17,12 +13,16 @@ test for the published npm artifact. ## Run -Install dependencies from this folder: +Install dependencies from the repo root: ```sh -npm install +yarn expo-example:install ``` +The install helper uses the published npm package when this SDK version exists. +Before publication, it packs the local SDK and installs that tarball into this +example. + Build and launch a development build: ```sh From 789bd6af793908f476cb7c48ab6637df156bc933 Mon Sep 17 00:00:00 2001 From: Tolgahan Date: Wed, 1 Jul 2026 18:23:30 +0300 Subject: [PATCH 5/5] docs: align example setup guidance --- AGENTS.md | 13 ++++++------- CONTRIBUTING.md | 7 ++++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 2f3aefa..2c673c2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -102,8 +102,9 @@ yarn lint # Run SDK example (React Native CLI) yarn sdk-example start -# Run Expo example (standalone — uses npm, not yarn workspace) -cd examples/expo-example && npm install && npm start +# Run Expo example +yarn expo-example:install +yarn expo-example ``` ## Testing @@ -123,11 +124,9 @@ plan for when automated tests are added. change. - The `lib/` directory is generated; never edit it by hand. - `examples/expo-example` is intentionally outside the Yarn workspace (`!examples/expo-example` in - `package.json#workspaces`) — install its deps with `npm`, not `yarn`. + `package.json#workspaces`) — install its deps from the repo root with `yarn expo-example:install`. - Native builds (Android/iOS) are slow; validate JS-layer changes with `yarn lint && yarn typecheck` first; leave full native builds to CI. -- The `resolutions` block in `package.json` pins `0xtrails` / `@0xtrails/*` — update all three - entries together when bumping the trails version. - Pre-release versions use the `0.x.y-alpha.N` scheme. Publishing steps are in `PUBLISHING.md`. ## CI/CD @@ -143,7 +142,8 @@ Android and iOS PR checks pass before merging; validate locally when you need fa ## Common Pitfalls - Running `yarn` inside `examples/expo-example` will fail — it's not a Yarn workspace member. Use - `npm` there, or `yarn expo-example